博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS 对象机制深剖——new 运算符
阅读量:6257 次
发布时间:2019-06-22

本文共 3833 字,大约阅读时间需要 12 分钟。

  • 其实关于 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  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  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  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  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.

本文转自艾伦 Aaron博客园博客,原文链接:http://www.cnblogs.com/aaronjs/archive/2012/07/04/2575570.html,如需转载请自行联系原作者
你可能感兴趣的文章
c#短信接口代码实现(发短信)
查看>>
nginx hello world模块编译运行的问题
查看>>
磁盘空间满引起的mysql启动失败:ERROR! MySQL server PID file could not be found!
查看>>
对症下药 避免显示器偏离色彩“正轨”
查看>>
MySQL权限经验原则
查看>>
apache下实现301永久性重定向的方法
查看>>
fir.im 持续集成技术实践
查看>>
windows快捷键使用
查看>>
Java 字符串处理
查看>>
安装nginx服务实战
查看>>
Python基础语法
查看>>
Net Standard扩展支持实例分享
查看>>
Xen虚拟机安装
查看>>
Varnish配置应用
查看>>
zstack虚拟机找不到硬盘信息
查看>>
Outlook客户端和Exchange服务器连接问题排错常用工具——Office配置扫描
查看>>
登录信息提示
查看>>
EXCHANGE2003系列总结-7:OWA下修改密码
查看>>
Zabbix安装图解教程
查看>>
oracle数据类型
查看>>