What's "new" in JavaScript?

老调重弹,在JavaScript中,遇到new操作符时执行了什么操作? 
也就是说new到底创造了什么,过程是怎样的? 
能否为Function对象增加一个原型方法,模拟new的操作? 
Js代码   收藏代码
  1. Function.prototype.__new__ = function(){  
  2.     var emptyFunction = function(){};  
  3.     emptyFunction.prototype = this.prototype;  
  4.     var newObject = new emptyFunction();  
  5.     newObject.__proto__ = this.prototype;  
  6.     newObject.constructor = this.prototype.constructor;  
  7.     var returnedObject = this.apply(newObject, arguments);  
  8.     return (typeof returnedObject === 'object' && returnedObject) || newObject;  
  9. };  

多数代码来自老道的 <<JavaScript: the Good Parts>> 
第5,6行是额外的一点补充: 
第5行:所有JS对象都有__proto__属性,指向 -- 构造器的prototype. (很多浏览器是可以访问到__proto__的,ie不行.) 

第6行:对象的constructor指向不一定是构造器,而是构造器的prototype对象的构造器,用一段代码说明: 
Js代码   收藏代码
  1. function Person(name){  
  2.     this.name = name;  
  3. }  
  4. Person.prototype = {  
  5.     getName:function(){  
  6.         return this.name;  
  7.     }  
  8. }  
  9. var p = new Person("a");  
  10. alert(p.constructor === Person); //false  
  11. alert(p.constructor === Object); //true 从第4行看到Person.prototype.constructor === Object 即Person.prototype = new Object(); Person.prototype.getName = function(){..}  

这样的constructor指向与constructor(构造器)的字面意义不搭,并不是我们期待的,往往会造成困扰.所以常见OO支持(YUI Kissy)通过显示的重写constructor维持对象的constructor的指向其构造器. 
但在对new的模拟中,需要保持与浏览器中new的做法一致:newObject.__proto__ = this.prototype; 

第2~4行:首先获取一个空的Function实例,获取构造器的prototype的引用,这就滤掉了构造器内定义的特有属性和特权方法.首要保障prototype的纯正血统.再用一段代码说明 
Js代码   收藏代码
  1. function Person(name,age){  
  2.     this.name = name;  
  3.     this.age = age;  
  4.     this.getAge = function(){//特权方法(privileged methods) 避免其被子类继承  
  5.         return this.age  
  6.     }  
  7. }  
  8. Person.prototype.getName = function(){ //原型方法 需要被其子类集成   
  9.     return this.name;  
  10. }//BTW: 通过这种方式为Person扩充原型方法,没有通过"="操作符为Person.prototype赋予新的对象(= new Objecct) 所以Person.prototype.constructor没有出现混乱.  


第7行:在保证了新创建对象的prototype的无增无损后,这一行代码保障特有属性和特权方法是新创建对象中依然是特有的,而且特有属性和特权方法和传入构造器的参数相关,通过apply方法将构造函数功能和传入参数作用于新构建的对象之上.将构造函数的返回值放入returnedObject暂存. 

第8行:新的对象已经创建好,如果returnedObject是非空对象则返回returnedObject,否则返回新创建的对象.returnedObject的这个判断也不难理解,我们可以利用这个特性创建单件(Singleton).比如这样写: 
Js代码   收藏代码
  1. function Singleton(){  
  2.     if(Singleton.inst){  
  3.         return Singleton.inst;  
  4.     }  
  5.     Singleton.inst = this;  
  6. }  
  7. var s1 = new Singleton();  
  8. var s2 = new Singleton();  
  9. alert(s1===s2);//true  


还有一个困扰,一旦Singleton前面没有new,Singleton.inst将指向window. 
其实所有类都需要判断是否是通过new进入的函数体.判断的方法不复杂,可以参照YUI使用instanceof判断: 
Js代码   收藏代码
  1. function Singleton(){  
  2.     if(this instanceof arguments.callee){ //如果没有通过new进入函数体,这里的this会指向window  
  3.         return new arguments.callee;  
  4.     }  
  5.     if(Singleton.inst){  
  6.         return Singleton.inst;  
  7.     }  
  8.     Singleton.inst = this;  
  9. }  
  10. var s1 = new Singleton();  
  11. var s2 = Singleton();  
  12. alert(s1===s2);//true  

这就是为Function增加原型方法__new__来做对new操作符的模拟,可能还不完善,但对理解一些JS内部机制有帮助.要是有错误,请一定帮忙指出~ 

最后,推荐看一下ECMA-262-3 in Detail系列文章.



转自:http://limu.iteye.com/blog/770539

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值