What's "new" in JavaScript?

老调重弹,在JavaScript中,遇到new操作符时执行了什么操作?
也就是说new到底创造了什么,过程是怎样的?
能否为Function对象增加一个原型方法,模拟new的操作?

Function.prototype.__new__ = function(){
var emptyFunction = function(){};
emptyFunction.prototype = this.prototype;
var newObject = new emptyFunction();
newObject.__proto__ = this.prototype;
newObject.constructor = this.prototype.constructor;
var returnedObject = this.apply(newObject, arguments);
return (typeof returnedObject === 'object' && returnedObject) || newObject;
};

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

第6行:对象的constructor指向不一定是构造器,而是构造器的prototype对象的构造器,用一段代码说明:

function Person(name){
this.name = name;
}
Person.prototype = {
getName:function(){
return this.name;
}
}
var p = new Person("a");
alert(p.constructor === Person); //false
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的纯正血统.再用一段代码说明

function Person(name,age){
this.name = name;
this.age = age;
this.getAge = function(){//特权方法(privileged methods) 避免其被子类继承
return this.age
}
}
Person.prototype.getName = function(){ //原型方法 需要被其子类集成
return this.name;
}//BTW: 通过这种方式为Person扩充原型方法,没有通过"="操作符为Person.prototype赋予新的对象(= new Objecct) 所以Person.prototype.constructor没有出现混乱.


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

第8行:新的对象已经创建好,如果returnedObject是非空对象则返回returnedObject,否则返回新创建的对象.returnedObject的这个判断也不难理解,我们可以利用这个特性创建单件(Singleton).比如这样写:

function Singleton(){
if(Singleton.inst){
return Singleton.inst;
}
Singleton.inst = this;
}
var s1 = new Singleton();
var s2 = new Singleton();
alert(s1===s2);//true


还有一个困扰,一旦Singleton前面没有new,Singleton.inst将指向window.
其实所有类都需要判断是否是通过new进入的函数体.判断的方法不复杂,可以参照YUI使用instanceof判断:

function Singleton(){
if(this instanceof arguments.callee){ //如果没有通过new进入函数体,这里的this会指向window
return new arguments.callee;
}
if(Singleton.inst){
return Singleton.inst;
}
Singleton.inst = this;
}
var s1 = new Singleton();
var s2 = Singleton();
alert(s1===s2);//true

这就是为Function增加原型方法__new__来做对new操作符的模拟,可能还不完善,但对理解一些JS内部机制有帮助.要是有错误,请一定帮忙指出~
最后,推荐看一下[url=http://dmitrysoshnikov.com/ecmascript/javascript-the-core/]ECMA-262-3 in Detail[/url]系列文章.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值