罗田县升平网络工作室,一家专业从事网站建设的工作室

资讯论坛

 找回密码
 加入论坛

快捷登录

回帖中禁止出现的内容,违者将被直接永久禁止访问,删除ID处理 :1.违反法律法规 ,包括但不限于出现带有政治、色情、暴恐信息等内容;2.恶意攻击内容,包括但不限于:恶意攻击党和政府、辱骂跟帖者、攻击主题发布者、不服从论坛管理、挑衅管理者、挑战版规等;3.广告、推广内容,尤其出现带有病毒、恶意代码、广告链接等内容,包括但不限于:QQ号、文字QQ号、微信号、手机号、文字手机号、第三方网址、单位公司名称、网站名称等;4.回帖贴出该主题隐藏资源链接或其它主题隐藏资源链接的行为。
查看: 227|回复: 0

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

[复制链接]

752

主题

650

帖子

712

积分

社区达人

积分
712
发表于 2021-11-12 09:20:20 | 显示全部楼层 |阅读模式
目录


  • 定义
  • 构造函数体不同

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

  • 构造函数类型不同

    • 构造函数为普通函数
    • 构造函数为箭头函数

  • 手写new
  • 总结

定义

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。
使用new [constructor]的方式来创建一个对象实例,但构造函数的差异会导致创建的实例不同。

构造函数体不同


构造函数也是函数,其唯一的区别就是调用方式不同,任何函数只要使用 new 操作符调用就是构造函数,而不使用 new 操作符调用的函数就是普通函数。
因此构造函数也可以带有返回值,但是这会导致new的结果不同。

无返回值

  1. function Person(name) {  this.name = name;}let obj = new Person("Jalenl");console.log(obj);
复制代码
显然,打印的是{name:'Jalenl'}

返回对象

  1. function Person(age) {  this.age = age;  return { name: "Jalenl" };}let obj = new Person(18);console.log(obj);
复制代码
打印的是{name:'Jalenl'},也就是说return之前的定义都被覆盖了。这里return的是一个对象,那返回的是个基本类型呢?

返回非对象

  1. function Person(age) {  this.age = age;  return 1;}let obj = new Person(18);console.log(obj);
复制代码
返回{age:21},这么说return失效了,跟没有return一样的结果,那如果没有this绑定内部属性,再返回基本数据类型呢?

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

  1. 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:
       
  • Create a new native ECMAScript object.   
  • Set the [[Class]] property of Result(1) to "Object".   
  • Get the value of the prototype property of F.   
  • If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).   
  • 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.   
  • 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.   
  • If Type(Result(6)) is Object then return Result(6).   
  • Return Result(1).
总结下来就是:
       
  • 在内存中创建一个新对象。   
  • 这个新对象内部的[[Prototype]]特性被赋值为构造函数的 prototype 属性。   
  • 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)。   
  • 执行构造函数内部的代码(给新对象添加属性)。   
  • 如果构造函数返回对象,则返回该对象;否则,返回刚创建的新对象(空对象)。
第五步就已经说明了构造函数不同导致new结果不同的原因。
以下摘自MDN的解释:
当代码 new Foo(…) 执行时,会发生以下事情:
       
  • 一个继承自 Foo.prototype 的新对象被创建。   
  • 使用指定的参数调用构造函数 Foo,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数列表,Foo 不带任何参数调用的情况。   
  • 由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)

构造函数为箭头函数


普通函数创建时,引擎会按照特定的规则为这个函数创建一个prototype属性(指向原型对象)。默认情况下,所有原型对象自动获得一个名为 constructor 的属性,指回与之关联的构造函数。
  1. function Person(){    this.age = 18;}Person.prototype/**{    constructor: ƒ Foo()    __proto__: Object}**/
复制代码
创建箭头函数时,引擎不会为其创建prototype属性,箭头函数没有constructor供new调用,因此使用new调用箭头函数会报错!
  1. const Person = ()=>{}new Person()//TypeError: Foo is not a constructor
复制代码
手写new


综上,熟悉了new的工作原理后,我们可以自己实现一个低配版的new,实现的关键是:
       
  • 让实例可以访问到私有属性;   
  • 让实例可以访问构造函数原型(constructor.prototype)所在原型链上的属性;   
  • 构造函数返回的最后结果是引用数据类型。
  1. 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原理与实现内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

来源:http://www.jb51.net/article/227135.htm
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
打赏鼓励一下!
回复

使用道具 举报

回帖中禁止出现的内容,违者将被直接永久禁止访问,删除ID处理 :1.违反法律法规 ,包括但不限于出现带有政治、色情、暴恐信息等内容;2.恶意攻击内容,包括但不限于:恶意攻击党和政府、辱骂跟帖者、攻击主题发布者、不服从论坛管理、挑衅管理者、挑战版规等;3.广告、推广内容,尤其出现带有病毒、恶意代码、广告链接等内容,包括但不限于:QQ号、文字QQ号、微信号、手机号、文字手机号、第三方网址、单位公司名称、网站名称等;4.回帖贴出该主题隐藏资源链接或其它主题隐藏资源链接的行为。

浏览排行

(38463)2019-11-5 公共云钱包资金盘骗局揭秘: 网络传销+原始股骗局合体!

(22233)2019-12-20 12月17日 邓智天法院直播庭审疑问全解答!

(20722)2019-12-1 环保币GEC资金盘骗局最新消息: 即将崩盘!

(17244)2019-11-9 巨胸肥臀大长腿,嫩模糯美子真人COS不知火舞福利污图

(15868)2018-12-24 罗田县人民法院公布【第五批失信被执行人名单】 ...

(14972)2019-11-3 曝光!PTFX已经崩盘跑路,投资者血流成河!

(13018)2019-8-7 湖北电力网上缴费,支付宝绑定户号的初始密码是什么?

(12480)2018-10-17 罗田县人民政府“12345”市民服务热线服务指南

(11170)2019-12-11 公安定性了, 趣码是非法传销! 趣码怎么退回365元?

(11081)2019-12-15 满足你对女同事的幻想 风骚秘书阿朱销魂眼神勾魂摄魄

最新发表

[升平网络工作室]2025-8-23 [2025-08-23]罗田天气预报

[升平网络工作室]2025-8-23 西藏自治区成立60周年庆祝大会隆重举行 习近平出席大会

[升平网络工作室]2025-8-23 县委委员会召开查摆问题整改整治情况汇报会

[爱查小程序]2025-8-22 [爱查]在线听音乐操作说明

[升平网络工作室]2025-8-22 [2025-08-22]罗田天气预报

[升平网络工作室]2025-8-22 习近平率中央代表团抵达拉萨出席西藏自治区成立60周年庆祝活动

[升平网络工作室]2025-8-22 县关工委联合经济开发区开展“情系学子”助学活动 助力职工子女圆梦大学

[升平网络工作室]2025-8-21 2025年罗田县卫健系统赴高校公开招聘事业单位工作人员拟聘用人员公示公告

[升平网络工作室]2025-8-21 [2025-08-21]罗田天气预报

[升平网络工作室]2025-8-21 县安防委2025年度第三次全体(扩大)会召开

QQ|Archiver|手机版|小黑屋|资讯论坛BBS.SPW8.CN ( 鄂ICP备2021011341号-3 )|网站地图


手机扫一扫继续访问
[免责声明]
本站系本网编辑转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。
如涉及作品内容、版权和其它问题,请在30日内与本网联系,我们将在第一时间删除内容!
[声明]本站文章版权归原作者所有 内容为作者个人观点 本站只提供参考并不构成任何投资及应用建议。

进入社区 | 发表新帖 | 百度收录 |
技术提供:罗田县升平网络工作室
站长Email:admin@spw8.cn
投诉电话(刮开查看):15374567400

GMT+8, 2025-8-23 17:01 , Processed in 0.631242 second(s), 30 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表