2013-12-17 65 views
3

我有一個關於如何定義原型屬性的問題。所以你不必寫「MyClass.prototype」。爲了將原型添加到每個屬性中,人們創建新的對象並將其設置爲原來的位置。定義原型屬性,正確的方法

像這樣。

var MyClass = function() {} 

MyClass.prototype = { 
    sayHi : function() { 
     alert('hi'); 
    } 
} 

但是,如果您這樣做,當您嘗試從任何實例訪問構造函數時可能會導致問題。

var o1 = new MyClass(); 

alert(o1 instanceof MyClass); // true 
alert(o1.constructor === MyClass); // false !!! 

o1.constructor通常會指向MyClass的,但由於原來的原型被改變,它不再。

我設法通過MyClass.prototype.constructor = MyClass;解決這個問題,它再次正常工作。

問題是,還有哪些其他問題可以改變原始原型?

你如何定義你的原型屬性?

+0

'構造函數'應該是不可枚舉的。 – SLaks

回答

1

您可以使用合併/擴展功能(在如jQuery或Lodash庫中常見的):

$.extend(MyClass.prototype, { prop: ..., ... }); 
+1

我可以想象,jQuery.extend使用「for循環」這被認爲是不好的做法,應該避免,除非它是絕對必要的。 –

+0

@ Python-:在for循環中迭代數組只是不好的做法。爲了循環對象成員,他們是正確的,推薦的,唯一的理智選擇。 (只是要小心原型) – SLaks

1

constructor屬性僅僅是一個方便的參考,你可以簡單地將其重新分配:

MyClass.prototype = { 
    constructor: MyClass, 
    sayHi : function() { 
     alert('hi'); 
    } 
} 

不應該有任何其他與重新定義原型對象相關的「問題」,除非你正在擴展另一個對象與預定義的原型屬性。

如果您想對自己的語法很勇敢,請嘗試使用with。我不會推薦它,但它仍然是一個選項,如果你只是想縮短語法:

var MyClass = function() {} 

with (MyClass.prototype) { 
    sayHi = function() { 
     alert('hi'); 
    } 
} 
+0

是的我知道,我在我的問題中說過,但我想知道它是否會導致任何其他問題。 –

+0

@ Python-請參閱我的編輯 – David

+0

「with」構造也被認爲是一種不好的做法:)儘管如此,根據你的寫法,我想你應該知道:D –

1

我通常選擇:

function MyClass() {} 

MyClass.prototype = { 
    constructor: MyClass, 

    foo: function foo() { 
     // do something 
    } 
}; 

我意識到這將覆蓋constructor屬性,但它維護起來比較乾淨,實際上我沒有注意到這10年來我一直在用這種方式編寫JavaScript類。

也可以使用原生Object.create方法。

前段時間我創建了一個小型的JavaScript庫,以協助在寫作課:Inherit.js

它允許你這樣創建類:

var Point = Object.extend({ 
    includes: [ 
     Mixin1, 
     Mixin2 
    ], 
    self: { 
     // class or "static" methods and properties go here 
    }, 
    prototype: { 
     // instance methods and properties go here 
    } 
}); 

var Point3D = Point.extend({ ... }); 

它提供了「混入」的支持好吧,如果他們這樣宣佈:

var Mixin = { 
    includes: [ 
     // Yup, mixins can include mixins too 
    ], 
    included: function(Klass) { 
     // Klass is the constructor function that just included this mixin 
    }, 
    self: { 
     // class or "static" methods and properties go here 
    }, 
    prototype: { 
     // instance methods and properties go here 
    } 
}; 

有些人會反對duck-typing native上課,但我全力以赴。

爲什麼我去這條路線:

  • instanceof算子仍然有效
  • 我想繼承實例和一流水平的方法
  • 我想要的東西,將與現有的大多數很好地工作的JavaScript框架
  • 混合支持,可以是一個方便的功能或柺杖,取決於情況。
+0

您可能還喜歡以下庫:https://github.com/javascript/augment –

2

我通常在JavaScript中創建「類」內而外使用簡單defclass功能:

function defclass(prototype) { 
    var constructor = prototype.constructor; 
    constructor.prototype = prototype; 
    return constructor; 
} 

此功能允許我如下創建類:

var MyClass = defclass({ 
    constructor: function() {}, 
    sayHi: function() { 
     alert("hi"); 
    } 
}); 

這種方法有以下優點:

  1. 所有原型pr operties封裝在單個對象文字中。
  2. constructor函數本身只是另一個原型屬性。
  3. 實例始終具有正確的constructor屬性。

例如:

var o1 = new MyClass; 
alert(o1 instanceof MyClass);  // true 
alert(o1.constructor === MyClass); // true 

你也可以很容易地修改defclass支持繼承:

function defclass(uber, body) { 
    var base = uber.prototype; 
    var prototype = Object.create(base); 
    var constructor = body.call(prototype, base), prototype.constructor; 
    constructor.prototype = prototype; 
    return constructor; 
} 

然後,您可以使用它,如下所示:

var Rectangle = defclass(Object, function() { 
    this.constructor = function (width, height) { 
     this.height = height; 
     this.width = width; 
    }; 

    this.area = function() { 
     return this.width * this.height; 
    }; 
}); 

繼承是也很簡單:

var Square = defclass(Rectangle, function (base) { 
    this.constructor = function (side) { 
     base.constructor.call(this, side, side); 
    }; 
}); 

一切正常:

var sq = new Square(5); 

alert(sq.area());     // 25 
alert(sq instanceof Square);  // true 
alert(sq instanceof Rectangle); // true 
alert(sq.constructor === Square); // true 

這是所有鄉親。