2013-12-17 36 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 

这是所有乡亲。