在我们手写new操作符时,首先我们要知道new操作符的作用是什么,这样我们在写的时候才一直知道自己在干嘛
new的作用
1.创建一个新的对象
2.把我们创建的对象的原型链和构造函数的原型对象连接在一起
3.把我们创建的对象的this指向构造函数的原型对象,因为我们需要用构造函数的方法
4.如果构造函数返回的是引用类型的值,那我们new的时候也返回这个值;如果构造函数返回是值类型,我们new的时候就返回我们创建的对象(我们此时返回的对象没有东西,只不过原型链上有构造函数的方法)
代码部分
function _new() {
let newObject = null;
let constructor = Array.prototype.shift.call(arguments);
let result = null;
// 判断参数是否是一个函数
if (typeof constructor !== "function") {
console.error("type error");
return;
}
// 新建一个空对象,对象的原型为构造函数的 prototype 对象
newObject = Object.create(constructor.prototype);
// 将 this 指向新建对象,并执行函数
result = constructor.apply(newObject, arguments);
// 判断返回对象
let flag = result && (typeof result === "object" || typeof result === "function");
// 判断返回结果
return flag ? result : newObject;
}
// 使用方法
_new(构造函数, 初始化参数);
我们只需要从上往下理清楚这几个问题,应该就可以明白为什么这样写啦
1.let constructor = Array.prototype.shift.call(arguments);是什么意思?
arguments是_new方法的类数组参数,没有数组的方法,因此需要用call来调用shift方法,作用是删除类数组的第一个值并且返回这个值,而这个值就是我们的构造函数。由于我们分别需要使用构造函数和参数,因此需要把构造函数单独取出来。
2.为什么需要增加一个判断if (typeof constructor !== "function")
由于constructor是构造函数,如果判断到不是构造函数,那就没有必要运行下去了,直接抛出错误即可
3.newObject = Object.create(constructor.prototype)创建的是一个什么东西?
首先需要知道Object.create(constructor.prototype)是什么意思,意思是创建出来的对象的_proto_指向constructor.prototype。所以这一步的主要作用就是完成new的第2个作用,创建出来的newObject对象的原型链连接到构造函数的原型对象上,接下来修改this指向即可
//Object.create()的手写比较简单
function create(obj) {
function F() {}
F.prototype = obj
return new F()
}
4.为什么result = constructor.apply(newObject, arguments)使用了apply方法
apply的作用是修改了this指向,即constructor的方法中的this指向了newObject。此时argument由于之前调用了shift方法,因此已经是剔除了构造函数,只剩下我们想传的参数。这一步完成了new作用的第三部,只剩最后一步啦!
//constructor的方法类似于
function constructor(name){
this.name = name
}
5.如何判断构造函数返回的值是引用类型还是值类型?
在第4步得出的result就是newObject执行了构造函数后返回的结果,那么我们只需要通过typeof判断result的类型即可。而与result进行和运算是多一层保障。然后就根据flag的值判断到底是返回构造函数返回的数据还是我们自己创建的对象啦
完结撒花