【JS】单身狗:怎样才能 new 一个对象呢?

164 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

平时我们再写 JS 代码的时候,经常会用到 new 运算符来创建一个新的对象实例。比如下面创建了一个 Vue 实例。(要是现实中的对象能 new 出来就好咯。。。)

new Vue({
    el: '#app'
});

但是你有去了解过 new 这个运算符是怎样创建一个对象实例的嘛?它到底做了啥事?

new 到底干了些啥

MDN 官方文档解释到,new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。

例子一

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

let person = new Person('hhhqzh');
console.log(person)
console.log(typeof person)

图片.png

从上面这个例子可以看出,new 操作符通过构造函数创建出一个对象

例子二

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

Person.prototype.sayName = function() {
    console.log(this.name)
}

let person = new Person('hhhqzh');
console.log(person.name); // 'hhhqzh'
person.sayName(); // 'hhhqzh'

图片.png 从上面这个例子可以看出,new 操作符创建出来的实例可以访问到构造函数原型链中的属性,也就是说通过 new 操作符把新创建的对象实例与构造函数通过原型链接起来了。

例子三

function Person(name){ 
    console.log('赋值前的this', this); // {} 
    this.name = name; 
    console.log('赋值后的this', this); // {name: 'hhhqzh'} 
} 

let person = new Person('hhhqzh');
console.log(person); // {name: 'hhhqzh'}

图片.png

从上面这个例子可以看出,new 操作符会把新创建的对象实例给绑定到构造函数的 this

例子四

当构造函数没有返回值时(默认返回 undefined

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

let person = new Person('hhhqzh');
console.log(person); // {name: 'hhhqzh'}

当构造函数返回一个非对象类型时

function Person(name) {
   this.name = name; 
   return 'hhhqzh'
}

let person = new Person('hhhqzh');
console.log(person); // {name: 'hhhqzh'}

当构造函数返回对象类型时

function Person(name) {
   this.name = name; 
   return {age: 18};
}

let person = new Person('hhhqzh');
console.log(person); // {age: 18}

图片.png

当构造函数没有返回值时或者返回了一个非对象类型的值时,这个返回值没有任何意义,new 操作符还是会返回 this,而当构造函数返回一个对象类型的值时,new 操作符就会返回这个对象,而非 this

总的来说,new 关键字会进行以下四步的操作:

  • 创建一个空的简单JavaScript对象(即{});
  • 为新创建的空对象添加属性 __proto__ ,将该属性链接至构造函数的原型对象;
  • 将新创建的对象作为this的上下文;
  • 如果该函数没有返回对象,则返回this,否则返回函数返回的对象。

模拟实现 new 操作符

function myNew(fn, ...args) {
    // 创建一个新对象
    let newObj = {};
    // 将新对象的 __proto__ 属性链接至构造函数的原型对象
    Object.setPrototypeOf(newObj, fn.prototype);
    // 将新对象绑定到构造函数并运行
    let result = fn.apply(newObj, args);
    // 判断构造函数的返回值是否为对象,如果是则返回,不是则返回 newObj
    return result instanceof Object ? result : newObj;
}

下面使用 myNew,与 new 操作符完全一致,没毛病!!

function Person(name, age) {
  this.name = name
  this.age = age
}
Person.prototype.sayName = function () {
    console.log(this.name)
}
const a = myNew(Person, 'hhhqzh', 18)
console.log(a.name) // 'hhhqzh'
console.log(a.age) // 18
a.sayName() // 'hhhqzh'

最后

欢迎大家在评论区一起交流,一起进步!