• 其实关于 new 的讨论,早有众多前辈做了先行。然而作为 JS 对象机制系列的一个重要成员,这一篇不可少,而且按照自己的惯例,我将首先引用语言规范的内容。另外,本篇引用到的规范内容比较多,不过我会做详细的说明,读者朋友可自行选择阅读规范内容。

考察 ECMAScript 语言规范中 new 运算符的定义:

The new Operator

The production NewExpression : new NewExpression is evaluated as follows:

  1. Evaluate NewExpression.
  2. Call GetValue(Result(1)).
  3. If Type(Result(2)) is not Object, throw a TypeError exception.
  4. If Result(2) does not implement the internal [[Construct]] method, throw a TypeError exception.
  5. Call the [[Construct]] method on Result(2), providing no arguments (that is, an empty list of arguments).
  6. Return Result(5).
  • 注意到,这段定义中的 new 后的表达式不带参数,即是说,这段内容针对的是诸如 obj = new Object; 这样的用法——带参数的用法如 str = new String(“test”); 将在下面给出。两者有区别且区别不大。

回到上述定义,其大意是,new 后必须跟一个对象并且此对象必须有一个名为 [[Construct]] 的内部方法(其实这种对象就是构造器),否则会抛出异常,比如:

var Str = "test";
var aStr = new Str;
// FF 显示“Str is not a constructor”
// IE 显示“对象不支持此操作”var Num = new Number(999);
var aNum = new Num;
// 结果同上

如果符合以上条件,那么引擎将调用其 [[Construct]] 内部方法,并不提供入口参数。接下来便要考察此内部方法。

另外,下面一段是 new 运算符的带参用法,由于和无参用法区别不大,读者朋友可直接略过。

The production MemberExpression : new MemberExpression Arguments is evaluated as follows:

  1. Evaluate MemberExpression.
  2. Call GetValue(Result(1)).
  3. Evaluate Arguments, producing an internal list of argument values (11.2.4).
  4. If Type(Result(2)) is not Object, throw a TypeError exception.
  5. If Result(2) does not implement the internal [[Construct]] method, throw a TypeError exception.
  6. Call the [[Construct]] method on Result(2), providing the list Result(3) as the argument values.
  7. Return Result(6).

考察 [[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 the 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).
  • 引擎将先创建一个语言原生对象,即“{}”或“new Object”,在此我们称之为 O,然后设置其内部属性标识 [[Class]] 为“Object”。接下来,得到构造器 F 的 prototype(根据后文的意思,它可能不是一个对象)。如果 F.prototype 是对象,那么将 O 的内部 [[Prototype]] 属性指向 F.prototype。
  • 请注意,诸如 [[Prototype]] 等为引擎内部标识符,对我们并不可见。[[Prototype]] 正是用于给内部维护原型链,虽然在我们看来,一个对象实例无法直接回溯到其原型(然而引擎内部可以),必须通过构造器中转,即 obj.constructor.prototype。
  • 接着,如果 F.prototype 不是 object,那么将 O 的内部 [[Prototype]] 属性指向“the Object prototype object”(你可以参考这里)。等到 O 的 [[Prototype]] 有了自己的归属以后,引擎调用构造器 F 的 [[Call]] 内部方法,以 O 作为 this 对象,并将传入 [[Construct]] 的参数作为入口参数——如果有的话(即诸如“new Object()”最后括号内的参数)传递过去。最后,如果 [[Call]] 的返回值是对象,那么创建成功并返回此对象,否则回头重来。

根据这些内容,我们完全可以构造一个伪 [[Construct]] 方法来模拟此流程(其实已有众多前辈做过此工作):

function MyObject(age) {this.age = age;
}MyObject.construct = function() {var o = {}, Constructor = MyObject;o.__proto__ = Constructor.prototype;// FF 支持用户引用内部属性 [[Prototype]]
Constructor.apply(o, arguments);return o;
};var obj1 = new MyObject(10);
var obj2 = MyObject.construct(10);
alert(obj2 instanceof MyObject);
// true

  • 到此,new 运算的过程已经描述得足够清楚了,然而,如果你还想继续了解内部方法 [[Call]] 的详情,不好意思,那就要牵涉到 JS 的函数闭包、作用域链,甚至深入到引擎对函数体的解析等内容了,这些又是 JS 的另外一个难点系列,在此便不多谈了。
附录
PROPERTY DESCRIPTION
[[CONSTRUCT]] Constructs an object. Invoked via the new operator. Objects that implement this internal method are called constructors.
[[CLASS]] A string value indicating the kind of this object.
[[CALL]] Executes code associated with the object. Invoked via a function call expression. Objects that implement this internal method are called functions.
[[PROTOTYPE]] The prototype of this object.

转载于:https://www.cnblogs.com/aaronjs/archive/2012/07/04/2575570.html

JS 对象机制深剖——new 运算符相关推荐

  1. C++ 异常机制深剖

    目录 传统艺能

  2. js 对象解构_JS对象:解构

    js 对象解构 JS对象:TL; DR (JS Objects: TL;DR) JavaScript has been plagued since the beginning with misunde ...

  3. JavaScript重难点解析5(对象高级、浏览器内核与事件循环模型(js异步机制))

    JavaScript重难点解析5(对象高级.浏览器内核与事件循环模型(js异步机制) 对象高级 对象创建模式 Object构造函数模式 对象字面量模式 工厂模式 自定义构造函数模式 构造函数+原型的组 ...

  4. JavaScript中BOM简介及其对象、js执行机制

    目录 BOM简介 什么是BOM DOM和BOM的区别 BOM的构成 Window对象的常见事件 窗口加载事件 调整窗口大小事件 定时器函数 setTimeout( )定时器 停止setTimeout( ...

  5. 从JS对象开始,谈一谈“不可变数据”和函数式编程

    文章转载自:https://segmentfault.com/a/1190000008780076 作为前端开发者,你会感受到JS中对象(Object)这个概念的强大.我们说"JS中一切皆对 ...

  6. 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理

    最近发现有不少介绍JS单线程运行机制的文章,但是发现很多都仅仅是介绍某一部分的知识,而且各个地方的说法还不统一,容易造成困惑. 因此准备梳理这块知识点,结合已有的认知,基于网上的大量参考资料,从浏览器 ...

  7. js中当等于最小值是让代码不执行_从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理...

    前言 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正. ----------超长文+多图预警,需要花费不少时间.---------- 如果看完本文后,还对进程线程傻傻分不清,不清楚浏 ...

  8. web前端培训JS 运行机制的梳理

    展现形式:由于是属于系统梳理型,就没有由浅入深了,而是从头到尾的梳理知识体系, 重点是将关键节点的知识点串联起来,而不是仅仅剖析某一部分知识. 内容是:从浏览器进程,再到浏览器内核运行,再到JS引擎单 ...

  9. JS 运行机制最全面的一次梳理

    前端Q 我是winty,专注分享前端知识和各类前端资源,乐于分享各种有趣的事,关注我,一起做个有趣的人- 公众号 点击上方 前端Q,关注公众号 回复加群,加入前端Q技术交流群 最近发现有不少介绍JS单 ...

最新文章

  1. java 初识对象和对象引用的关系
  2. js 将线性数据转为树形
  3. 那个专攻JVM的00后求职者,薪水比我的还高···
  4. 我的Android进阶之旅------gt;Java全角半角的转换方法
  5. Observer Pattern分析
  6. MyBatis下MySqL用户口令不能为空
  7. 数据库基础知识——DQL语言(二)
  8. 手机端公告文本回滚(简单的jq代码)
  9. 牛客网 [编程题]餐馆
  10. iOS ffmpeg + libfdk-aac
  11. VS附加依赖项以及Opencv配置问题
  12. deepsort报错 No module named ‘sklearn.utils.linear_assignment_‘ 问题解决
  13. 操作系统文件的物理结构(文件分配方式)
  14. 微信\支付宝扫码条码区分规则
  15. 比方便面还方便~利用Python开发一个桌面小程序
  16. 告别2018:人间值得,你更值得!
  17. 国外android内存清理工具,给大家推荐一个安卓清理神器哈,确实好用
  18. RSS是什么意思?(转)
  19. SH7218T拆解手记(12)IWNN(日文输入)的移植
  20. rj45 千兆接口定义_网线的RJ45接口的针脚定义

热门文章

  1. Windows Store App JavaScript 开发:小球运动示例
  2. android overridePendingTransition
  3. mysql 怎么导入函数_mysql导入导出包括函数或者存储过程_MySQL
  4. canvas之一:绘制直线
  5. git rebase用法
  6. leetcode算法题--骑士在棋盘上的概率★
  7. setuid与capability
  8. Linux 安装Resin4.0.40
  9. 《OpenACC并行程序设计:性能优化实践指南》一 3.5 在应用程序执行期间记录性能信息...
  10. /etc/issue、shutdown命令详解