实现一个new操作符

530 阅读2分钟

来源:segmentfault.com/a/119000002…

new做了什么?

new操作符,通过执行自定义构造函数或js内置的构造函数,从而生成一个实例对象。

例1.1

function Person(name) {
    this.name = name;
}
let p = new Person('jack')
console.log(p)
console.log(p.__proto__ === Person.prototype)

上述demo操作:

1.new执行Person构造函数后,返回一个内部创建的新对象实例,并赋值给p。

2.this指向这个创建的新对象。

3.p的__proto__指向构造函数Person的prototype,实例p能够访问到Person构造函数原型中的属性和方法。

例1.2

function Person(name) {
    this.name = name;
    return {age: 18}
}
let p = new Person('jack')
console.log(p)


上述demo:

构造函数返回了一个对象,结果将其直接返回,而不是返回内部创建的新对象。

上述两个例子,以及相关测试,总结出:

引用类型object或者function,即Function,Object,Array,Date,Error,Regexp。(typeof null == 'Object',记得排除null)。返回这些类型就会直接将其返回。

其他基本类型都会返回内部创建的新对象。


new内部操作步骤

现在再来理解new内部操作步骤,就会容易很多:

1.创建一个空的简单JavaScript对象(即{})

2.链接该对象(即设置该对象的构造函数)到另一个对象;

3.将步骤1新创建的对象作为this的上下文;

4.如果函数没有返回对象,则返回this。


实现一个new操作符

接下来,我们尝试实现一个new操作符

封装方法myNew接受若干参数,第一个参数ctr为构造函数,其余为构造器所需参数arg1,arg2...

第一步

对应new内部操作步骤的1和2步,即创建和链接。

方法1

function myNew(ctr) {
    let obj = Object.create(ctr.prototype)
}

方法2

function myNew(ctr) {
    let obj = {};
    obj.__proto__ = ctr.prototype;
}

第二步

上下文执行。

function myNew(ctr) {
    let obj = Object.create(ctr.prototype)
    
    const args = [].slice.call(arguments,1)
     //或者  const args = Array.from(arguments).slice(1)
     //或者  const args = [...arguments].slice(1)

   let result = ctr.apply(obj,args)
}

第三步

对返回值做兼容处理

function myNew(ctr) {
    let obj = Object.create(ctr.prototype)
    
    const args = [].slice.call(arguments,1)
    let res = ctr.apply(obj,args)

     if ((typeof res === "object" || typeof res === "function") && res !== null) {
        return res ;
     }
    return obj
}

此时,再看上面两个例子,就能很好的理解。