慎用prototype={...}

>
慎用prototype={...}

    在网上见过很多人创建JavaScript类时喜欢将所有的实例方法都以上下文(Context)的方式赋值给对象的prototype属性:

function Obj() {
    this.prop1 = 'prop1'; // instance property
    this.prop2 = 'prop2';
}
Obj.staticProp = 'Static Prop';
Obj.staticMethod = function () {
    // do some static behavior
};
Obj.prototype = {
    method1: function() {
        // do somthing
    },
    method2: function() {
        // do somthing
    }
};

这样做看起来使创建类的代码更加简洁明了,但是内部隐藏着不少可能出现的问题。如你所见到,Obj.prototype = {...}这
条语句是用上下文(即{}匿名对象)把对象的prototype属性完完全全地覆盖掉,这意味着以前prototype生来具有的一些内部方
法现在都不存在了
。而这也就是出现问题的地方。举一个例子,假如你想利用上述方法创建对象,但是你还想很集中地定义类
的静态属性和方法,进而考虑利用对象的constructor函数属性来向创建对象的类追加方法(注意,这个例子的思路可能会产生
问题,比如我们想不创建实例的情况下直接使用静态方法或属性等,但是请记住,这只是一个为了说明上述代码创建对象可能会
产生的潜在问题,与本例的易用性无关。),那么你的代码可能会是这样:
function Obj() {
    this.prop1 = 'prop1'; 
// instance property
    this.prop2 = 'prop2';
    
    this._init();
}
Obj.prototype = {
    _init: 
function () {
        _init: 
function () {
        this.constructor.staticProp = '
Static Prop';
        this.constructor.staticMethod = 
function () {
                
// do some static behavior
        };
    },
    method1: 
function() {
        
// do somthing
    },
    method2: 
function() {
        
// do somthing
    }
};

但是你会发现这段代码根本就不起作用,类Obj并没有获得任何的静态属性或方法。这是怎么回事呢?其实原因就是obj=prototype
{...}这段代码覆盖了原有对象obj的prototype属性

    首先我们来回顾一下一个对象实例是如何创建的:构造函数把它的prototype原型对象中的所有属性及方法拷贝一份给新的实例。
在这里我的构造函数就是function Obj(){},而constructor也是创建实例的构造函数(即Obj)的引用。但是我们是通过this方式来
调用的,那么我们应该调用的是由构造函数Obj的prototype所拷贝而来的所有的属性和方法,但是我们发现通过Obj.prototype{...},
构造函数的prototype除了_init, method1, method2之外无任何其他方法(of course,constructor方法也没有,所以this.constructor失效了~~~)。改进的方法很简单,就是不要去覆盖prototype,而是要向prototype对象追加属性和方法。所以改进后的方法可能是这样的:
function Obj() {
    this.prop1 = 'prop1'; 
// instance property
    this.prop2 = 'prop2';
    
    this._init();
}
Obj.prototype._init = 
function () {
    this.constructor.staticProp = 'Static Prop';
    this.constructor.staticMethod = 
function () {
        
// do some static behavior
    };
};
Obj.prototype.method1 = 
function() {
        
// do somthing
};
Obj.prototype.method2 = 
function() {
        
// do somthing
};

虽然我也不是很赞成去修改原始对象,但有时真的会起到事半功倍的效果。在这里我再向大家推荐一种方法,就是向Funtion对象的prototype属性中追加方法(这样以后所有的function函数对象就都具备了这个方法。其实用function定义的函数都是Function类的实例化),代码如下:
Function.prototype.extend = function (oContext, bIsStatic) {
    var oThis = (typeof bIsStatic != 'undefined' && bIsStatic)? this: this.prototype;
    for ( var prop in oContext) {
        oThis[prop] = oContext[prop];
    }
};
function Obj() {
    this.prop1 = 'prop1'; // instance property
    this.prop2 = 'prop2';
}
// Append Static Methods or Properties
Obj.extend({
    staticProp: 'staticProp',
    staticMethod: function () {
        // do some static behavior
    }
}, true);
// Append Instance Methods or Properties
Obj.extend({
    method1: function() {
        // do somthing
    },
    method2: function() {
        // do somthing
    }
});

利用我刚才定义的extend方法,就可以轻松而又简洁地向Obj类中添加静态和实例属性或方法,而且已经解决上面所提到的所有问题。

posted @ 2008-11-08 11:11  eliuhy  阅读(738)  评论(0编辑  收藏  举报