JS 对象机制深剖——new 运算符
- 其实关于 new 的讨论,早有众多前辈做了先行。然而作为 JS 对象机制系列的一个重要成员,这一篇不可少,而且按照自己的惯例,我将首先引用语言规范的内容。另外,本篇引用到的规范内容比较多,不过我会做详细的说明,读者朋友可自行选择阅读规范内容。
考察 ECMAScript 语言规范中 new 运算符的定义:
The new Operator
The production NewExpression : new NewExpression is evaluated as follows:
- Evaluate NewExpression.
- Call GetValue(Result(1)).
- If Type(Result(2)) is not Object, throw a TypeError exception.
- If Result(2) does not implement the internal [[Construct]] method, throw a TypeError exception.
- Call the [[Construct]] method on Result(2), providing no arguments (that is, an empty list of arguments).
- 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:
- Evaluate MemberExpression.
- Call GetValue(Result(1)).
- Evaluate Arguments, producing an internal list of argument values (11.2.4).
- If Type(Result(2)) is not Object, throw a TypeError exception.
- If Result(2) does not implement the internal [[Construct]] method, throw a TypeError exception.
- Call the [[Construct]] method on Result(2), providing the list Result(3) as the argument values.
- Return Result(6).
考察 [[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 the 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).
- 引擎将先创建一个语言原生对象,即“{}”或“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 运算符相关推荐
- C++ 异常机制深剖
目录 传统艺能
- js 对象解构_JS对象:解构
js 对象解构 JS对象:TL; DR (JS Objects: TL;DR) JavaScript has been plagued since the beginning with misunde ...
- JavaScript重难点解析5(对象高级、浏览器内核与事件循环模型(js异步机制))
JavaScript重难点解析5(对象高级.浏览器内核与事件循环模型(js异步机制) 对象高级 对象创建模式 Object构造函数模式 对象字面量模式 工厂模式 自定义构造函数模式 构造函数+原型的组 ...
- JavaScript中BOM简介及其对象、js执行机制
目录 BOM简介 什么是BOM DOM和BOM的区别 BOM的构成 Window对象的常见事件 窗口加载事件 调整窗口大小事件 定时器函数 setTimeout( )定时器 停止setTimeout( ...
- 从JS对象开始,谈一谈“不可变数据”和函数式编程
文章转载自:https://segmentfault.com/a/1190000008780076 作为前端开发者,你会感受到JS中对象(Object)这个概念的强大.我们说"JS中一切皆对 ...
- 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理
最近发现有不少介绍JS单线程运行机制的文章,但是发现很多都仅仅是介绍某一部分的知识,而且各个地方的说法还不统一,容易造成困惑. 因此准备梳理这块知识点,结合已有的认知,基于网上的大量参考资料,从浏览器 ...
- js中当等于最小值是让代码不执行_从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理...
前言 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正. ----------超长文+多图预警,需要花费不少时间.---------- 如果看完本文后,还对进程线程傻傻分不清,不清楚浏 ...
- web前端培训JS 运行机制的梳理
展现形式:由于是属于系统梳理型,就没有由浅入深了,而是从头到尾的梳理知识体系, 重点是将关键节点的知识点串联起来,而不是仅仅剖析某一部分知识. 内容是:从浏览器进程,再到浏览器内核运行,再到JS引擎单 ...
- JS 运行机制最全面的一次梳理
前端Q 我是winty,专注分享前端知识和各类前端资源,乐于分享各种有趣的事,关注我,一起做个有趣的人- 公众号 点击上方 前端Q,关注公众号 回复加群,加入前端Q技术交流群 最近发现有不少介绍JS单 ...
最新文章
- java 初识对象和对象引用的关系
- js 将线性数据转为树形
- 那个专攻JVM的00后求职者,薪水比我的还高···
- 我的Android进阶之旅------gt;Java全角半角的转换方法
- Observer Pattern分析
- MyBatis下MySqL用户口令不能为空
- 数据库基础知识——DQL语言(二)
- 手机端公告文本回滚(简单的jq代码)
- 牛客网 [编程题]餐馆
- iOS ffmpeg + libfdk-aac
- VS附加依赖项以及Opencv配置问题
- deepsort报错 No module named ‘sklearn.utils.linear_assignment_‘ 问题解决
- 操作系统文件的物理结构(文件分配方式)
- 微信\支付宝扫码条码区分规则
- 比方便面还方便~利用Python开发一个桌面小程序
- 告别2018:人间值得,你更值得!
- 国外android内存清理工具,给大家推荐一个安卓清理神器哈,确实好用
- RSS是什么意思?(转)
- SH7218T拆解手记(12)IWNN(日文输入)的移植
- rj45 千兆接口定义_网线的RJ45接口的针脚定义
热门文章
- Windows Store App JavaScript 开发:小球运动示例
- android overridePendingTransition
- mysql 怎么导入函数_mysql导入导出包括函数或者存储过程_MySQL
- canvas之一:绘制直线
- git rebase用法
- leetcode算法题--骑士在棋盘上的概率★
- setuid与capability
- Linux 安装Resin4.0.40
- 《OpenACC并行程序设计:性能优化实践指南》一 3.5 在应用程序执行期间记录性能信息...
- /etc/issue、shutdown命令详解