new 操作符具体干了什么

MDN 上描述如下:

  1. 创建一个空的简单Javascript对象 (即{ })
    2. 将构造函数赋给该空对象的constructor
  2. 链接空对象的原型和构造函数的原型 (设置该构造函数的prototype为新创建空对象的 __proto__
  3. 将新创建的对象作为 this 的上下文(即将构造函数的作用域赋给新对象)
  4. 如果该构造函数没有返回对象,则返回 this

我认为 第二步 应该和网上大多数说的一样,将构造函数的原型传递给新建对象的隐式原型(__proto__),如果是将构造函数直接赋值给新建对象的隐式原型上的 constructor 那么这个构造出来的新对象,还具有原生对象的一些属性。如下图:

根据MDN和网上参考的一些解释,得出如下实现的代码

    const customNew = (constructor) => {
        let obj = {}
         obj.__proto__ = constructor.prototype
        return function () {
            constructor.apply(obj, arguments)
            return obj
        }
    }

然后让我们来使用一下

    function Person(name, age) {
        this.name = name;
        this.age = age;
    }

    Person.prototype.sayName = function() {
        console.log(this.name);
    } 

    let person1 = new Person("ming", 12)
    let person2 = customNew(Person)("hong", 11)
    console.log(Person.prototype);
    console.log(person1);
    console.log(person2);
貌似功能都完善得差不多了,但是如果构造函数有返回值的话就会出错了
    function Person(name, age) {
        this.name = name;
        this.age = age;
        return {
            age: this.age
        }
    }

结合构造函数的内部原理:

  1. 在函数体前隐式加上 this = {}
  2. 执行 this.xxx = xxx
  3. 隐式返回 this

最终代码如下:

    const customNew = (constructor) => {
        //1. 创建一个空的简单Javascript对象 (即{ })
        let obj = {}
        //2. 将构造函数的原型和对象的原型关联
        obj.__proto__ = constructor.prototype
        return function () {
            //3. 为新创建的对象添加属性
            const res = constructor.apply(obj, arguments)
            if(res instanceof Object) { //4. 如果该构造函数没有返回对象,则返回 this
                return res
            } else {
                return obj
            } 
        }
    }

具体使用:

function Foo(name) {
    this.name = name;
}

let obj = customNew(Foo)("obj");
console.log(obj);

你可能感兴趣的:(new 操作符具体干了什么)