new

作为大家天天使用的操作符,想必大家都不陌生

创建一个对象的通用语法

let obj = new Object();

那么在创建对象的过程中,new 到底做了什么?

MDN

当代码 new Foo(...) 执行时,会发生以下事情:(MDN地址)

  • 一个继承自 Foo.prototype 的新对象被创建。
  • 使用指定的参数调用构造函数 Foo ,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数列表,Foo 不带任何参数调用的情况。
  • 由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)

按照这个过程,我们可以大概的模拟一个new的实现

function _new(Super) {
    //返回一个function
    return (props)=> {
        let obj = {}; //创建一个新对象
        obj.__proto__ = Super.prototype;//继承父类的属性
        let result = Super.apply(obj,props);//调用Super的构造函数
        return typeof result === 'object'? result : obj;; //判断Super构造器总返回一个Object
    }
}

var a = _new(Super)(['z'])
a;//{name: "z"}

ECMA-262

再次阅读Ecma262
其过程较MDN多了一些判断,如:

new Object ( [ value ] )
当以一个参数 value 或者无参数调用 Object 构造器,采用如下步骤:

  1. 如果提供了 value, 则
    a.如果 Type(value) 是 Object, 则

      (1)如果 value 是个原生 ECMAScript 对象 , 不创建新对象,简单的返回 
      value.
      (2)如果 value 是宿主对象 , 则采取动作和返回依赖实现的结果的方式可以使 
      依赖于宿主对象的 .

    b.如果 Type(value) 是 String, 返回 ToObject(value).
    c.如果 Type(value) 是 Boolean, 返回 ToObject(value).
    d.如果 Type(value) 是 Number, 返回 ToObject(value).

  2. 断言 : 未提供参数 value 或其类型是 Null 或 Undefined.
  3. 令 obj为一个新创建的原生 ECMAScript 对象 .
  4. 设定 obj 的 [[Prototype]] 内部属性为标准内置的 Object 的 prototype 对象.
  5. 设定 obj 的 [[Class]] 内部属性为 "Object".
  6. 设定 obj 的 [[Extensible]] 内部属性为 true.
  7. 设定 obj 的 8.12 指定的所有内部方法
  8. 返回 obj.

重新来修改下我们的模拟

function _new(Super) {
    //返回一个function
    return (value) => {
        if (value) {
            switch (typeof value) {
                case 'object':
                    //这里因为不同的宿主环境也就是不同的引擎会有不同的写法,找了很多博文书籍也没有详解具体的判断逻辑或方法,只好先写伪代码了
                    if (宿主对象) {
                        //采取动作和返回依赖实现的结果的方式可以使依赖于宿主对象的
                    } else {
                        return value
                    }
                    break;
                case 'string':
                    return new String(value);
                    break;
                case 'boolean':
                    return new Boolean(value);
                    break;
                case 'number':
                    return new Number(value);
                    break;
                default:
                    break;
            }
        }
        let obj = {}; //创建一个新对象
        obj.__proto__ = Super.prototype; //继承父类的属性
        //修改内部属性class 为 “Object”,不过ecma262没有提供任何方法去修改,只提供了一种访问方法 Object.prototype.toString.call("我们的对象")
        //修改内部属性Extensible为 true,不过目前没有提供方法去修改,只有一个修改为false Object.preventExtensions("我们的对象");
        let result = Super.apply(obj, value); //调用Super的构造函数
        return typeof result === 'object' ? result : obj;; //判断Super构造器总返回一个Object
    }
}

var a = _new(Super)(['z'])
a; //{name: "z"}

clipboard.png

欢迎补充


ThenMorning
190 声望18 粉丝

但行好事,莫问前程.