Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

彻底捋清楚 new 的实现 #37

Open
amandakelake opened this issue Mar 25, 2018 · 0 comments
Open

彻底捋清楚 new 的实现 #37

amandakelake opened this issue Mar 25, 2018 · 0 comments

Comments

@amandakelake
Copy link
Owner

amandakelake commented Mar 25, 2018

先给出最终版,后面会解析难点

实现

  1. 声明一个中间对象
  2. 将该中间对象的原型指向构造函数的原型
  3. 将构造函数的this,指向该中间对象
  4. 返回该中间对象,即返回实例对象
function newF() {
  // 创建一个新的对象
  let obj = {};
  // 取出第一个参数,该参数就是我们将会传入的构造函数,比如在调用new(P)的时候,Constructor就是P本身
  // arguments会被shift去除第一个参数,剩余的就是构造器P的参数
  let Constructor = [].shift.call(arguments);
  // 将obj的原型指向构造函数,此时obj可以访问构造函数原型中的属性
  obj.__proto__ = Constructor.prototype;
  // 改变构造函数的this的指向,使其指向obj, 此时obj也可以访问构造函数中的属性了
  let result = Constructor.apply(obj, arguments);
  // 确保 new 出来的是个对象 返回的值是什么就return什么
  return typeof result === 'object' ? result : obj 
}

难点

其实这短短的几行代码里面,浓缩了几个知识点,请先自行查阅

  • 如何绑定this, call、apply使用
  • arguments使用
  • 原型链基础

这两行代码,很多同学会在这里懵逼

let Constructor = [].shift.call(arguments);
let result = Constructor.apply(obj, arguments);

复制如下代码到控制台打印一下

function P(firstName, lastName) {
  this.age = 10;
  this.getName = function() {
    return `${firstName} ${lastName}`;
  };
}

function newF() {
  let obj = new Object();
  console.log('刚开始时的arguments', arguments);
  let Constructor = [].shift.call(arguments);
  console.log('被shift后的arguments', arguments);
  console.log('- - - - -- - - -- -- - - ');
  console.log('Constructor', Constructor);
  console.log('- - - - -- - - -- -- - - ');
  obj.__proto__ = Constructor.prototype;
  let result = Constructor.apply(obj, arguments);
  console.log('绑定this时的arguments', arguments)
}

let p = newF(P, 'amanda', 'kelake');

36a384f9-b811-4dad-be39-cb2e54066878

如图,刚开始时传入的arguments代表的是传入newF的参数,第一个参数arguments[0]自然就是传入的构造器P

let Constructor = [].shift.call(arguments);

shift后(直接从数组里面删除元素),构造器P被拿出,arguments这时候代表的就是构造器P所需要的传入参数firstName, lastName
然后把构造器P的this指向将要return的新实例对象,并把剩余参数传入

let result = Constructor.apply(obj, arguments);

使用

function P(firstName, lastName) {
  this.age = 10;
  this.getName = function() {
    return `${firstName} ${lastName}`;
  };
}

function newF() {
  let obj = new Object();
  let Constructor = [].shift.call(arguments);
  obj.__proto__ = Constructor.prototype;
  let result = Constructor.apply(obj, arguments);
  return typeof result === 'object' ? result : obj 
}

let p = newF(P, 'amanda', 'kelake');
p.getName();
// "amanda kelake"

后记

感谢您耐心看到这里,希望有所收获!

如果不是很忙的话,麻烦点个star⭐【Github博客传送门】,举手之劳,却是对作者莫大的鼓励。

我在学习过程中喜欢做记录,分享的是自己在前端之路上的一些积累和思考,希望能跟大家一起交流与进步,更多文章请看【amandakelake的Github博客】

@amandakelake amandakelake changed the title 自己动手实现new 彻底捋清楚new实现 Apr 10, 2018
@amandakelake amandakelake changed the title 彻底捋清楚new实现 彻底捋清楚 new 的实现 Apr 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant