实现 new 运算符的方法
解析:
要实现 new 运算符的方法,首先要明白使用 new 来调用函数,或者说发生构造函数调用时,会执行哪些操作:
- 创建(或者说构造)一个全新的对象
- 这个新对象会被执行 [[prototype]] 连接
- 这个新对象会绑定到函数调用的 this
- 执行这个函数里面的语句
- 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象
代码:
function _new(){
//1.拿到传入参数中的第一个参数,即构造函数名 Func
var Func = [].shift.call(arguments);
//2.创建一个空对象obj,并让其的隐式原型__proto__ 指向 构造函数的显式原型 Func.prototype
var obj = Object.create(Func.prototype);
//第二步也可以用以下方式:
//var obj = {};
//obj.__proto__ = Func.prototype;
//3.执行构造函数,并将 this 指向新创建的空对象 obj
var ret = Func.apply(obj,arguments);
//4.如果构造函数的返回值是对象则直接返回,否则返回新创建的对象 obj
return typeof ret === 'object' ? ret : obj;
}
//测试
function Person(name,age){
this.name = name;
this.age = age;
}
var p1 = _new(Person,'LL',18);
console.log(p1);
//结果如下:
Person {name: "LL", age: 18}
name: "LL"
age: 18
__proto__:
constructor: ƒ Person(name,age)
length: 2
name: "Person"
arguments: null
caller: null
prototype: {constructor: ƒ}
__proto__: ƒ ()
[[FunctionLocation]]: VM258:21
[[Scopes]]: Scopes[1]
__proto__: Object
Obect.create()方法创建一个新对象,使用现有对象来提供新对象的__proto__。
如何理解 [].shift.call(arguments)
因为 shift 内部实现是使用的 this 代表调用对象,那么当 [].shift.call() 传入 arguments 对象的时候,通过 call 函数改变原来的 shift 方法的 this 指向,使其指向 arguments ,并对 arguments 进行复制操作,而后返回一个新数组。至此便完成了 arguments 类数组转为数组的目的,其实这可以理解为,让类数组调用数组的方法。
也可以写成 Array.prorotype.shift.call(arguments);当然可以直接使用 es 6 的扩展运算符 [...arguments] 或者 Array.from(arguments) 直接将其转化为数组再进行操作。