先给出最终版,后面会解析难点
实现
- 声明一个中间对象
- 将该中间对象的原型指向构造函数的原型
- 将构造函数的this,指向该中间对象
- 返回该中间对象,即返回实例对象
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');
如图,刚开始时传入的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博客】