首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

7.4  识别new运算进行的构造器调用

说明:

在一个函数中识别当前调用是使用new来进行的构造器调用,还是普通的函数或方法调用。

示例背景:

如果一个函数被设计为既可以用new运算来产生对象实例,又可以作为普通函数调用,或者可以作为对象方法调用,那么如何识别当前究竟在哪种环境下被调用呢?

示例代码:

175        /**

176         * 1. 识别当前函数是否使用new运算来构建实例

177         */

178        function MyObject() {

179          if (this instanceof arguments.callee) {

180            // 是使用new运算构建实例

181          }

182          else {

183            // 是普通函数调用 

184          }

185        }

186        var obj = new MyObject();

187         

188        /**

189         * 2. 识别当前函数是否使用作为方法调用

190         */

191        function foo() {

192          if (this === window) {

193            // 是普通函数调用

194          }

195          else {

196            // 是方法调用

197          }

198        }

199        obj.aMethod = foo;

200        obj.aMethod();

示例说明:

当使用new运算时,构建过程运行在函数自身的闭包中,而且新构建的对象总是构造器的一个实例。因此,示例1使用arguments.callee来找到这个构造器函数自身,并检测this对象是否为它的实例,从而可以检测是否运行在new运算的实例构建过程中。

但这种方法存在一个(唯一的)问题。如果用户代码试图将构造器函数作为它的实例的一个方法,那么示例1就会误判。例如:

obj.aMethod = MyObject;

obj.aMethod(); // <-- 这个方法调用会被识别为new()构建过程

这时,除非用户代码愿意使用更为复杂的构造过程,在MyObject()中加入更多的识别代码并与构造器原型等采用某种特别的约定,否则上述的误判问题是不可能解决的。

除了示例1所示的方法之外,用户代码也可以用一种简洁的方法来识别new运算中的构造器调用:

5                 if (this.constructor === arguments.callee) {

6                   ...

这种方法依赖于构建器原型的constructor属性,因此要求MyObject的原型或该原型的constructor成员未被重写过。这种方法虽然有些限制,但仍然是常常用到的。

示例2利用了一条简单的规则:在普通函数调用中,this引用指向宿主对象——在浏览器环境中是window,如果是在其他环境中,请参考相关文档。

当用户代码使用aFunction.apply或aFunction.call来调用函数自身时,可能会显式地指定this引用为null、undefined等无意义的值。这种情况下,JavaScript引擎内部会忽略该值,并以宿主对象作为this引用传入函数。因此我们不必额外地检测这些值。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论