new和Object.create()手写+分析

一、new

“new XXX类”的时候到底做了什么呢?

  1. 创建了一个对象
  2. 让这个实例对象的__proto__ (隐式原型)指向类的prototype(显式原型)
    • 对象天生会有一个属性__proto__,一般实例对象的__proto__会指向把它new出来的类的prototype
    • 不明确是谁new出来的实例,那它的__proto__指向Object的prototype
    • 为什么要这样呢?打个比方,小红的妈妈Mother类的一个实例,Mother类原型上有一个方法----唠叨。那当小红的妈妈.唠叨的时候,小红的妈妈不需要自己有唠叨这个方法,她可以顺着原型链(小红的妈妈.__proto__ === Mother.prototype)找到Mother类的原型,就可以使用里面的唠叨。
  3. 将类当普通函数执行,并且this指向第一步创建的实例对象
  4. 如果执行完,返回的结果是一个引用类型值(比如对象,方法),那就返回这个结果;否则只能返回刚刚创建的实例对象
那就来写代码吧~:
/*
 *   @params
 *      Func:类
 *      ...params:要传递给类的参数
 *   @return
 *      引用类型值|实例对象
 */
function _new(Func, ...params) {
    //第一步--创建一个对象
    let obj = {};
    //第二步--让他的__proto__指向类的prototype
    obj.__proto__ = Func.prototype;
    //第三步--将类当普通函数执行,并且让他的this是刚刚创建的实例对象obj
    let result = Func.call(obj, ...params);
    //第四步--检测一下本来执行结束是不是返回的是引用类型值(null的时候typeof结果也是object,所以要排除掉),是就返回该结果,不是就返回obj
    return (result !== null && /^(function|object)$/i.test(typeof result)) ? result : obj;
}

//Mother类
function Mother(name) {
    this.name = name;
}
Mother.prototype.laodao = function laodao() {
    console.log("你怎么还不起床??");
}

//来试试写的new行不行
let mother = _new(Mother, "DaHong");
mother.laodao();// =>你怎么还不起床??
可是__proto__在IE是被保护起来的,所以来优化一下:
function _new(Func, ...params) {
    //第一步--创建一个对象 + 第二步--让他的__proto__指向类的prototype
    let obj = Object.create(Func.prototype);
    //第三步--将类当普通函数执行,并且让他的this是刚刚创建的实例对象obj
    let result = Func.call(obj, ...params);
    //第四步--检测一下本来执行结束是不是返回的是引用类型值(null的时候typeof结果也是object,所以要排除掉),是就返回该结果,不是就返回obj
    return (result !== null && /^(function|object)$/i.test(typeof result)) ? result : obj;
}

二、Object.create()

既然刚刚优化的时候用到了Object.create(params),那就一起分析+手写一下吧?

  1. 创建一个空对象
  2. 将该对象的__proto__j指向传递进来的形参

等等!!这个第二步是不是和new能完成的第二步很像,只是new是指向new的那个类。所以我们可以借助new写这个函数(因为还是要考虑__proto__不能在IE下操作)。既然要借助new,那是不是得要有一个类,那步骤就是如下~

  1. 创建一个类(空函数)
  2. 让类的prototype指向传进来的params
  3. new 第一步创建的类并返回(那么按照new会做的事情,是不是创建出来的实例的__proto__就可以指向类的prototype,也就是params了呢~~)
所以代码如下~
Object.create = function create(params) {
    // 第一步
    function Func() {};
    // 第二步
    Func.prototype = params;
    // 第三步
    return new Func;
}
优化一下,如果传递进来的params不是个对象,就扔个错误~
Object.create = function create(params) {
    if (params === null || typeof params !== "object") {
        throw new TypeError("Object prototype may only be an Object");
    }

    // 第一步
    function Func() { };
    // 第二步
    Func.prototype = params;
    // 第三步
    return new Func;
}

完成啦~~~


版权声明:本文为weixin_44044238原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。