老调重弹,在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;
- };
多数代码来自老道的 <<JavaScript: the Good Parts>>
第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);
- alert(p.constructor === Object);
这样的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(){
- return this.age
- }
- }
- Person.prototype.getName = function(){
- return this.name;
- }
第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);
还有一个困扰,一旦Singleton前面没有new,Singleton.inst将指向window.
其实所有类都需要判断是否是通过new进入的函数体.判断的方法不复杂,可以参照YUI使用instanceof判断:
- function Singleton(){
- if(this instanceof arguments.callee){
- return new arguments.callee;
- }
- if(Singleton.inst){
- return Singleton.inst;
- }
- Singleton.inst = this;
- }
- var s1 = new Singleton();
- var s2 = Singleton();
- alert(s1===s2);
这就是为Function增加原型方法__new__来做对new操作符的模拟,可能还不完善,但对理解一些JS内部机制有帮助.要是有错误,请一定帮忙指出~
最后,推荐看一下ECMA-262-3 in Detail系列文章.
转自:http://limu.iteye.com/blog/770539