😾 New的原理

new 关键词的主要作用就是执行一个构造函数、返回一个实例对象,在 new 的过程中,根据构造函数的情况,来确定是否可以接受参数的传递。下面我们通过一段代码来看一个简单的 new 的例子

🍊 new的执行过程

new 操作符可以帮助我们构建出一个实例,并且绑定上 this,内部执行步骤可大概分为以下几步:
  • 📕 创建一个新对象
  • 📕 对象连接到构造函数原型上,并绑定 this(this 指向新对象)
  • 📕 执行构造函数代码(为这个新对象添加属性)
  • 📕 返回新对象

例外

如果不用 new 这个关键词,结合上面的代码改造一下,去掉 new,会发生什么样的变化呢?我们再来看下面这段代码
// 'use strict';

function Person() {
    this.name = "江小白";
}

var p = Person();
console.log(p); //undefined
console.log(name) //江小白
console.log(p.name); // Cannot read property 'name' of undefined
  • 📔 从上面的代码中可以看到,我们没有使用 new 这个关键词,返回的结果就是 undefined。其中由于 JavaScript 代码在默认情况下 this 的指向是 window,那么 name 的输出结果就为江小白,这是一种不存在 new 关键词的情况。
  • 📔 那么当构造函数中有 return 一个对象的操作,结果又会是什么样子呢?我们再来看一段在上面的基础上改造过的代码。
function Person() {
    this.nem = "江小白";
    return { age: 22 };
}

var p = new Person();
console.log(p); //{ age: 22 }
console.log(p.name); //undefined
console.log(p.age); //22

通过这段代码又可以看出,当构造函数最后 return 出来的是一个和 this 无关的对象时,new 命令会直接返回这个新对象,而不是通过 new 执行步骤生成的 this 对象

但是这里要求构造函数必须是返回一个对象,如果返回的不是对象,那么还是会按照 new 的实现步骤,返回新生成的对象。接下来还是在上面这段代码的基础之上稍微改动一下

function Person(){
   this.name = '江小白'; 
   return 'tom';
}
var p = new Person(); 
console.log(p)  // {name: '江小白'}
console.log(p.name) // 江小白
💝 因此我们总结一下:new 关键词执行之后总是会返回一个对象,要么是实例对象,要么是 return 语句指定的对象

✏️ 手写实现new

//  手写模拟new
function myNew(fn, ...args) {
    if (typeof fn !== 'function') {
        throw 'fn mast be a function';
    }
    // 1. 用new Object()创建一个对象obj
    var obj = new Object();
    // 2. 给该对象的__proto__赋值为fn.prototype,即设置原型链
    obj.__proto__ = Object.create(fn.prototype);
    // 3. 执行fn,并将obj作为内部this。使用 apply,
    // 改变构造函数 this 的指向到新建的对象,
    // 这样 obj 就可以访问到构造函数中的属性
    var result = fn.apply(obj, args); 
    // 4. 如果fn有返回值,则将其作为new操作返回,否则返回obj
    return result instanceof Object ? result : obj;
}

🔖 test

// test 
function Person(...args) {
  console.log(args)
}
// 使用内置函数new
var person1 = new Person(1,2)
console.log(person1)
// 使用手写的new,即create
var person2 = myNew(Person, 1, 2)
console.log(person2)
new 被调用后大致做了哪几件事情
  • 📒 让实例可以访问到私有属性;
  • 📒 让实例可以访问构造函数原型(constructor.prototype)所在原型链上的属性;
  • 📒 构造函数返回的最后结果是引用数据类型。

@不负代码不负漆
16 声望9 粉丝

专注于前端开发,对前沿技术有高度关注


« 上一篇
js的几种继承
下一篇 »
单列模式