【JS】new 做了什么?

67 阅读2分钟

声明:下面主要是写 new 的内部实现原理,但其中涉及到的其它东西,也会作出适当的说明

一. 实现步骤

  1. 创建一个新对象
  2. 将新对象的 __proto__ 指向 构造函数的 prototype (利用 Object.create())
  3. 将 构造函数的 this 指向 新对象(利用 call 或者 apply)
  4. 判断返回值类型 —— 如果是基本类型,则返回新对象;如果是引用类型,则返回该引用类型的对象

二. 实现代码

function myNew(){
    // 创建一个新对象
    let newObj = null;
    
    // 这行代码的意思是,将 shift 方法的 this 绑定为 arguments(类数组),并且由 arguments 调用,删除并返回 arguments 中的第一个值,然后再判断这个值是否是(构造)函数。此后 arguments 中就只包括构造函数的所有参数,而不包括构造函数本身
    let constructor = Array.prototype.shift.call(arguments);
    
    // 判断是否是(构造)函数
    if(typeof constructor !== "function"){
        console.log("type error");
        return;
    }
    
    // 将 新对象的 __proto__ 指向 构造函数的 prototype
    newObj = Object.create(constructor.prototype)
    
    // 将 构造函数的 this 指向 新对象,并接收 构造函数的返回结果
    // let result = constructor.call(newObj, ...arguments);
    let result = constructor.apply(newObj, arguments);
    
    // 如果 构造函数 没有返回值,或者是 直接 return; 则 result 为 undefined
    // 如果 构造函数 返回的是基本类型,则 result 为 基本类型
    // 如果 构造函数 返回的是引用类型,则 result 为 引用类型
    // 判断 返回结果是什么
    let flag = result && (typeof result === "object" || typeof result === "function");
    
    // 如果 result 为 引用类型,则 flag 为 true,直接返回这个 引用类型对象,否则返回 新对象
    return flag ? result : newObj;
}

// 使用方法 
objectFactory(构造函数, 初始化参数);

三. 其它

1. 在函数形参中接收的 ...args 和 arguments 对象的区别

(1) ...args 是接收剩余参数,组成一个真数组,可以调用 Array 原型上的方法;而 arguments 是一个类数组,包括了所有参数,并且有 length 属性和其它的一些附加属性(如 callee)

(2) ...args 要写在函数的形参列表中;而 arguments 可以不写在函数形参列表中,可以直接使用

2. Object.create() 的作用和实现

(1) 作用:将传入的对象作为原型

(2) 实现:

function create(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}

3. call、apply、bind 的作用、应用和实现