tip:先弄懂原型和原型链再看new的实现
new 的实现流程
- 生成一个新对象
- 链接对象,将新创建的对象__proto__指向到对应原型对象上
- 将上下文,设置为新建对象的指针(this)
- 如果构造函数没有返回对象类型,则返回新建的对象。
流程解析:
- 为什么要生成一个新对象?
- 新的实例,需要新的内存引用
- 因为任意对象都有属性__proto__
- 为什么要将__proto__指向原型对象?
- 在调用对象属性时,如果当前对象没有这个属性,会从__proto__中寻找,因为__proto__指向原型对象,相当于复用原型对象的方法。
- 符合原型链规则,因为js底层设计如此,最终指向都是null。
- 为什么要将上下文,设置为新建对象的指针(this)?
- 构造函数初始化,会形成新的引用,确保形成完整的原型链。
- 为什么如果构造函数没有返回对象类型,则返回新建的对象?
- new 结果必须返回一个对象引用,如果构造函数没有返回对象,我们也不返回新建对象的话,那么会导致new的结果指向undefined,javascript是不运行undefined设置属性,最终导致调用方错误异常。
完整实现
/**
* @description new 的实现
* @param {Function} ctor [构造函数]
* @return {Object|Function|Regex|Date|Error} [结果]
*/
function fakeNew (ctor) {
// 加一下类型保护,确保构造函数是函数
if (typeof ctor !== 'function') {
throw 'Are you kidding me?It need constructor'
}
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new.target
// ES6 规定 new.target 指向构造函数,是为了入开发者检测是否是new实例化的。
fakeNew.target = ctor;
// 1.创建一个新对象
// 2.顺便将__proto__指向到构造函数的prototype
var newObj = Object.create(ctor.protoType);
// 因为构造函数有初始化的行为,所以获取剔除构造函数余下的参数传入构造函数
var args = [].slice.call(arguments, 1);
// 执行构造函数
var res = ctor.apply(newObj, args);
var isObj = res === null || typeof res === 'Object';
var isFn = typeof res === 'function';
if(isObj || isFn) {
return res;
}
// 构造函数没有返回对象,则返回新建对象
return newObj;
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END