昨晚看了一篇模拟实现 js new 的文章,今天复盘一下
function a(){
this.b = 'bb';
}
a.prototype.c = 'cc';
var aa = new a();
new 其实做了三件事情,首先它肯定是创建了一个对象
2.将 a 的prototype属性对象通过引用传递赋值给 aa.__proto__ ,相当于:aa.__proto__ = a.prototype
进一步证实一下:
第三件事:用对象 aa 调用函数 a,从而使 a 内部的 this 指向 aa,即:
a.apply(aa)
这样 aa 就有了属性 b
这样我们就用上面的三步“生产”出了一个和 new 效果一样的对象 bb;
以上就是 new 的基本原理了,但还有一些小细节 :
1. 函数a 如果有参数
2. 函数 a 如果有返回值
1 : 比较简单,修改第三步为 a.apply(bb , [arg1, arg2, ...]) 就可以了
2 : 分两种情况:
a.返回值类型为基本类型: string number null undefined boolean symbol
b.返回值为对象 即,typeof 等于 'object' 或 'function' ,这里面包含了 Array、Date、RegExp、Error 等。。。
情况 a 是我们上面讲的普通情况,
但是当我们 new 一个返回值为对象的函数时,js 不会执行上面的那些操作,而是执行函数并返回函数的发回值 即:
new a(); 和 a(); 的效果是一样的:
所以如果要自己模拟一个 new 函数可以这样写:
function newOperator(ctor){
if(typeof ctor !== 'function'){
throw 'newOperator function the first param must be a function';
}
//es6 new.target 指向构造函数(这个没有细究)
newOperator.target = ctor;
//这里可以通过 Object.create 将第一二步合成一步
var newObj = Object.create(ctor.prototype);
var argsArr = [].slice.call(arguments);
argsArr.shift();
var ctorReturnResult = ctor.apply(newObj, argsArr);
if(typeof ctorReturnResult === 'object' && ctorReturnResult !== null){
return ctorReturnResult;
}
if(typeof ctorReturnResult === 'function'){
return ctorReturnResult;
}
return newObj;
}
当然 js 也赋予了 prototype __proto__ 这些特殊属性一些特殊作用,
比如 可以用 aa.c 来访问 aa.__proto__.c 前提是 aa 没有 c 这个自有属性,并且不能通过 aa.c 来修改 aa.__proto__.c 即:
aa.c = 'ss' 是不能改变 aa.__proto__.c 的值
__________________________________________________________
所以,清楚了 __proto__ 是一个对象引用,并且了解了它的特殊作用 js 的原型链 面向对象 也就明白八成了吧~~!