我的编程空间,编程开发者的网络收藏夹
学习永远不晚

深入聊一聊JS中new的原理与实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

深入聊一聊JS中new的原理与实现

定义

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

使用new [constructor]的方式来创建一个对象实例,但构造函数的差异会导致创建的实例不同。

构造函数体不同

构造函数也是函数,其唯一的区别就是调用方式不同,任何函数只要使用 new 操作符调用就是构造函数,而不使用 new 操作符调用的函数就是普通函数。

因此构造函数也可以带有返回值,但是这会导致new的结果不同。

无返回值


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

let obj = new Person("Jalenl");
console.log(obj);

显然,打印的是{name:'Jalenl'}

返回对象


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

let obj = new Person(18);
console.log(obj);

打印的是{name:'Jalenl'},也就是说return之前的定义都被覆盖了。这里return的是一个对象,那返回的是个基本类型呢?

返回非对象


function Person(age) {
  this.age = age;
  return 1;
}

let obj = new Person(18);
console.log(obj);

返回{age:21},这么说return失效了,跟没有return一样的结果,那如果没有this绑定内部属性,再返回基本数据类型呢?

没有属性绑定+返回非对象


function Person(){
    return 1
}
new Person()

返回的是一个空对象{},意料之中。

综上,只有构造函数return返回的是一个对象类型时,才能改变初始结果。

构造函数类型不同

构造函数为普通函数

ECMA-262 3rd. Edition Specification中的说明了对象实例的创建过程:

13.2.2 [[Construct]]
When the [[Construct]] property for a Function object F is called, the following steps are taken:

  1. Create a new native ECMAScript object.
  2. Set the [[Class]] property of Result(1) to "Object".
  3. Get the value of the prototype property of F.
  4. If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).
  5. If Result(3) is not an object, set the [[Prototype]] property of Result(1) to the original Object prototype object as described in 15.2.3.1.
  6. Invoke the [[Call]] property of F, providing Result(1) as the this value and providing the argument list passed into [[Construct]] as the argument values.
  7. If Type(Result(6)) is Object then return Result(6).
  8. Return Result(1).

总结下来就是:

  1. 在内存中创建一个新对象。
  2. 这个新对象内部的[[Prototype]]特性被赋值为构造函数的 prototype 属性。
  3. 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)。
  4. 执行构造函数内部的代码(给新对象添加属性)。
  5. 如果构造函数返回对象,则返回该对象;否则,返回刚创建的新对象(空对象)。

第五步就已经说明了构造函数不同导致new结果不同的原因。

以下摘自MDN的解释:

当代码 new Foo(…) 执行时,会发生以下事情:

  1. 一个继承自 Foo.prototype 的新对象被创建。
  2. 使用指定的参数调用构造函数 Foo,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数列表,Foo 不带任何参数调用的情况。
  3. 由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)

构造函数为箭头函数

普通函数创建时,引擎会按照特定的规则为这个函数创建一个prototype属性(指向原型对象)。默认情况下,所有原型对象自动获得一个名为 constructor 的属性,指回与之关联的构造函数。


function Person(){
    this.age = 18;
}
Person.prototype

创建箭头函数时,引擎不会为其创建prototype属性,箭头函数没有constructor供new调用,因此使用new调用箭头函数会报错!


const Person = ()=>{}
new Person()//TypeError: Foo is not a constructor

手写new

综上,熟悉了new的工作原理后,我们可以自己实现一个低配版的new,实现的关键是:

  1. 让实例可以访问到私有属性;
  2. 让实例可以访问构造函数原型(constructor.prototype)所在原型链上的属性;
  3. 构造函数返回的最后结果是引用数据类型。

function _new(constructor, ...args) {
    // 构造函数类型合法判断
    if(typeof constructor !== 'function') {
      throw new Error('constructor must be a function');
    }
    // 新建空对象实例
    let obj = new Object();
    // 将构造函数的原型绑定到新创的对象实例上
    obj.__proto__ = Object.create(constructor.prototype);
    // 调用构造函数并判断返回值
    let res = constructor.apply(obj,  args);
    let isObject = typeof res === 'object' && res !== null;
    let isFunction = typeof res === 'function';
    // 如果有返回值且返回值是对象类型,那么就将它作为返回值,否则就返回之前新建的对象
    return isObject || isFunction ? res : obj;
};

这个低配版new实现可以用来创建自定义类的实例,但不支持内置对象,毕竟new属于操作符,底层实现更加复杂。

总结

到此这篇关于JS中new的原理与实现的文章就介绍到这了,更多相关JS中new原理与实现内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

深入聊一聊JS中new的原理与实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

一文聊聊Vue-Router的实现原理

路由的概念相信大部分同学并不陌生,我们在用 Vue 开发过实际项目的时候都会用到 Vue-Router 这个官方插件来帮我们解决路由的问题。它的作用就是根据不同的路径映射到不同的视图。今天我们主要是谈谈Vue-Router的实现原理,感兴趣的小伙伴可以继续往下看。
2023-05-14

一起来聊聊JavaScript事件循环的原理与实例

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了事件循环的相关内容,下面一起来看一下,希望对大家有帮助。
2022-11-22

深入剖析OpenMP锁的原理与实现

在本篇文章当中主要给大家介绍一下 OpenMP 当中经常使用到的锁并且仔细分析它其中的内部原理!文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
2023-01-28

JavaScript中new操作符的原理与实现详解

你知道new吗?你知道new的实现原理吗?你能手写new方法吗?不要担心,这篇文件就来带大家深入了解一下JavaScript中的new操作符,感兴趣的小伙伴可以学习一下
2022-11-13

深入浅析java 中HashMap的实现原理

这篇文章将为大家详细讲解有关深入浅析java 中HashMap的实现原理,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1. HashMap的数据结构数据结构中有数组和链表来实现对数据的存储,
2023-05-31

深入理解PHP trait DTO的实现原理与核心逻辑

引言:在PHP编程中,对象的数据传输对象(Data Transfer Object)在实际开发中起到了非常重要的作用。特别是在复杂的应用中,数据传输对象可以简化代码结构、提高代码可读性和可维护性。本文将深入探讨PHP中使用trait来实现数
2023-10-21

深入探讨Go语言同步机制的原理与实现

Go语言作为一种面向并发编程的语言,在其同步机制设计中引入了goroutine、channel以及select语句等特性,使得并发编程变得更加容易和高效。本文将深入探讨Go语言同步机制的原理与实现,并结合具体的代码示例进行讲解。1. Go
深入探讨Go语言同步机制的原理与实现
2024-03-02

深入理解Python虚拟机中描述器的实现原理

这篇文章主要给大家介绍一个我们在使用类的时候经常使用但是却很少在意的黑科技——描述器的实现原理,文中的示例代码讲解详细,需要的可以参考一下
2023-05-19

深入探究len函数在Python中的实现原理:深入理解其底层机制

深入理解Python中的len函数:掌握其底层实现原理,需要具体代码示例引言:Python是一门简洁、易读、容易上手的编程语言。在Python中,len()函数是一种非常常用的内置函数,用于返回某个容器对象(如字符串、列表、元组等)的元素
深入探究len函数在Python中的实现原理:深入理解其底层机制
2024-01-13

深入理解Python虚拟机中调试器实现原理与源码分析

本文主要给大家介绍python中调试器的实现原理,通过了解一个语言的调试器的实现原理我们可以更加深入的理解整个语言的运行机制,可以帮助我们更好的理解程序的执行,感兴趣的可以了解一下
2023-05-17

编程热搜

目录