new关键字源码

579 阅读2分钟

由于本文涉及到原型原型链、this指向等知识,如果不太清楚这方面的知识可以下:原型原型链可看下我写的另一篇文章:
轻松理解JS原型原型链,this指向推荐大家看下这篇文章**:**this、apply、call、bind

一:new 的实现原理

  1. 创建一个空对象

  2. 实例的__proto__ 和原型对象指向同一个地方(不理解可以看下轻松理解JS原型原型链

  3. 执行构造函数方法,改变了Person中的this指向(不理解可以看下this、apply、call、bind),属性和方法被添加到obj引用的对象中

  4. 执行构造函数返回结果result,如果result是基本数据类型(数字、字符串、布尔类型等和null)会忽略返回值,返回obj此时的person01就是这个obj); 如果result的是对象,则返回result

二:模拟实现

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

var person01 = new Person("Monica","Galen")
// new做了以下隐式操作
new Person{
    // 步骤1:创建了一个空对象
    var obj = {};
    //  步骤2...
    obj.__proto__ = Person.prototype;   
    // 步骤3...
    var result = Person.apply(obj,"Monica","Galen");
    // 步骤4...
    return (typeof result === 'object' && result) || obj
}

三: 源码实现

如果new是一个方法而不是一个运算符,它可能会这样执行

// 在 Function的原型对象上添加了一个method方法
Function.prototype.method = function (name, func) {
  this.prototype[name] = func;
  return this;
};

// 由于 Function.__proto__ = Function.prototype, Function上有了method方法
// 执行了method方法后,Function的 prototype上有了new方法
Function.method("new", function () {
  // 步骤1:创建一个新对象,步骤2:它继承自构造函数的原型对象
  var that = Object.create(this.prototype);

  // 步骤3:调用构造函数,绑定this到新对象上
  var other = this.apply(that, arguments);

  // 步骤4:如果它的返回值不是对象,就返回该that对象
  return (typeof other === "object" && other) || that;
});

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

// 由于 Person.__proto__ = Function.prototype,所以Person有了new方法
let person01 = Person.new("Ross");
console.log(person01);
// 此时我们打印 person01;可以看看 person01是什么;并且
person01.__proto__ === Person.prototype; // true

// 我们在用原来的方式创建person02
let person02 = new Person("Chandler");
console.log(person02);

// 发现了吗?Object.create其实就是利用空对象实现原型链继承
// Object.create 源码实现
// Object.create = function(o){
//     function F();
//     F.prototype = o;
//     return new F();
// }