yuanyuanbyte/Blog

JavaScript 深入系列之 new 操作符的模拟实现

yuanyuanbyte opened this issue · 0 comments

本系列的主题是 JavaScript 深入系列,每期讲解一个技术要点。如果你还不了解各系列内容,文末点击查看全部文章,点我跳转到文末

如果觉得本系列不错,欢迎 Star,你的支持是我创作分享的最大动力。

new的原理是什么?new的模拟实现?通过new的方式创建对象和通过字面量创建有什么区别?

new

一句话介绍 new:

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。(来自MDN)

new 关键字会进行如下的操作:

  1. 创建一个空的简单JavaScript对象(即{});
  2. 链接该对象(设置该对象的constructor)到另一个对象 ;
  3. 将步骤1新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this

实现new

new 关键字进行的操作:

  1. 创建一个空的简单JavaScript对象(即{});
  2. 链接该对象(设置该对象的constructor)到另一个对象 ;( 通俗理解就是新对象隐式原型__proto__链接到构造函数显式原型prototype上。)
  3. 将步骤1新创建的对象作为this的上下文 ;( 实际是执行了构造函数 并将构造函数作用域指向新对象 )
  4. 如果该函数没有返回对象,则返回this。( 实际是返回一个空对象, new Object()就是返回一个空对象{} )

由于无法模拟JS关键字,我们只能创建一个函数myNew来模拟。这个函数当中,第一个参数就是构造函数,第二个参数开始,是构造函数中的参数。

使用 apply,改变构造函数 this 的指向到新建的对象,这样 obj 就可以访问到构造函数中的属性,并带参执行函数。

如果构造函数有返回值,则返回;否则,就会默认返回新对象。

但是,new这个关键字,并不是所有返回值都原封不动地返回的。如果返回的是undefinednull以及基本类型的时候,都会返回新的对象;而只有返回对象的时候,才会返回构造函数的返回值。

因此,我们要判断result是不是object类型,如果是object类型,那么就返回result,否则,返回obj。

下面是实现new的代码:

function myNew(constructor, ...arg) {
  var obj = {}; // 对应于上面的步骤 1
  
  obj.__proto__ = constructor.prototype; // 对应于上面的步骤 2
  
  var res = constructor.apply(obj, arg); // 对应于上面的步骤 3
  
  return typeof res === 'object' ? res : obj; // 对应于上面的步骤 4
}


// 测试代码
function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
       console.log(this.name)
    }
}

// var person = new Person('Nicholas', 29, 'Front-end developer'); 
var person = myNew(Person, 'Nicholas', 29, 'Front-end developer');

console.log(person.name) // Nicholas
person.sayName();        // Nicholas
console.log(person.__proto__ === Person.prototype);   // true

了解 new 关键字的内部实现后,就不难理解为什么构造函数内的 this 会被绑定到新创建的对象上了。

通过new的方式创建对象和通过字面量创建有什么区别?

字面量创建对象,不会调用 Object构造函数, 简洁且性能更好;

因为你使用 new Object() 的方式创建对象需要调用Object()构造函数,本质上是方法调用,涉及到在__proto__链中遍历该方法,当找到方法后,会产生调用方法必须的堆栈信息,方法结束后,需要释放堆栈,在性能上不如使用字面量的方式创建对象。

重要参考

查看全部文章

博文系列目录

  • JavaScript 深入系列
  • JavaScript 专题系列
  • JavaScript 基础系列
  • 网络系列
  • 浏览器系列
  • Webpack 系列
  • Vue 系列
  • 性能优化与网络安全系列
  • HTML 应知应会系列
  • CSS 应知应会系列

交流

各系列文章汇总:https://github.com/yuanyuanbyte/Blog

我是圆圆,一名深耕于前端开发的攻城狮。

weixin