我想知道使用其中任何一种是否有任何优势,我应该走哪条路?
构造方法:
var Class = function () {
this.calc = function (a, b) {
return a + b;
};
};
原型方法:
var Class = function () {};
Class.prototype.calc = function (a, b) {
return a + b;
};
我不喜欢这样,使用原型,方法定义与类分开,我不知道是否有任何特定的原因我应该使用它而不是第一种方法。
此外,使用函数文字来定义“类”是否有任何好处,而不仅仅是函数定义:
var Class = function () {};
VS
function Class () {};
谢谢!
答案 0 :(得分:436)
通过原型链继承的方法可以针对所有实例进行普遍更改,例如:
function Class () {}
Class.prototype.calc = function (a, b) {
return a + b;
}
// Create 2 instances:
var ins1 = new Class(),
ins2 = new Class();
// Test the calc method:
console.log(ins1.calc(1,1), ins2.calc(1,1));
// -> 2, 2
// Change the prototype method
Class.prototype.calc = function () {
var args = Array.prototype.slice.apply(arguments),
res = 0, c;
while (c = args.shift())
res += c;
return res;
}
// Test the calc method:
console.log(ins1.calc(1,1,1), ins2.calc(1,1,1));
// -> 3, 3
注意如何更改应用于这两个实例的方法?这是因为ins1
和ins2
共享相同的calc()
功能。为了使用在构造期间创建的公共方法执行此操作,您必须将新方法分配给已创建的每个实例,这是一项尴尬的任务。这是因为ins1
和ins2
会有自己独立创建的calc()
函数。
在构造函数中创建方法的另一个副作用是性能较差。每次构造函数运行时都必须创建每个方法。原型链上的方法创建一次,然后由每个实例“继承”。在硬币的另一面,公共方法可以访问“私有”变量,这对于继承的方法是不可能的。
至于您的function Class() {}
vs var Class = function () {}
问题,前者在执行前被“提升”到当前范围的顶部。对于后者,变量声明被提升,但不是赋值。例如:
// Error, fn is called before the function is assigned!
fn();
var fn = function () { alert("test!"); }
// Works as expected: the fn2 declaration is hoisted above the call
fn2();
function fn2() { alert("test!"); }
答案 1 :(得分:64)
原型方法的优点是效率。在所有calc()
个对象之间共享一个Class
函数对象(我指的是通过调用Class
构造函数创建的对象)。另一种方式(在构造函数中分配方法)为每个Class
对象创建一个新的函数对象,使用更多的内存并在调用Class
构造函数时花费更多的处理时间。但是,这种方法确实有一个优点:calc()
方法可以访问构造函数中的局部变量,您可以利用这些变量:
function Class() {
var calcCallCount = 0;
this.calc = function (a, b) {
++calcCallCount;
alert("Calc called " + calcCallCount + " times");
return a + b;
};
};
关于var Class = function() {...}
与function Class() {...}
,我通常更喜欢后者是因为它意味着函数有一个名称,这在调试时很有用。另一个区别是后一版本(函数声明)被提升,这意味着它在定义范围内的任何地方都可用,而不仅仅是在定义之后。但是,some people更喜欢在任何地方使用前者(函数表达式)。
答案 2 :(得分:42)
var YourClass = function(){
var privateField = "somevalue";
this.publicField = "somevalue";
this.instanceMethod1 = function(){
//you may access both private and public field from here:
//in order to access public field, you must use "this":
alert(privateField + "; " + this.publicField);
};
}
YourClass.prototype.instanceMethod2 = function(){
//you may access only public field 2 from this method, but not private fields:
alert(this.publicField);
//error: drawaback of prototype methods:
alert(privateField);
};
原型方法的优点:
通过原型定义方法时,它们在所有YourClass实例之间共享。结果,这种情况的总大小<1。比如在构造函数中定义方法;有些测试显示了通过原型的方法定义如何减少html页面的总大小,从而降低了加载速度。
通过原型定义的方法的另一个优点是,当您使用继承的类时,您可以覆盖此类方法,并且在派生类的overriden方法中,您可以调用具有相同名称的基类方法,但是使用构造函数中定义的方法,您无法执行此操作。
答案 3 :(得分:-4)
首先,你应该像这样使用对象文字:
var Class = {
calc: function (a, b) {
return a + b;
}
};
这种表示法更清晰,而且很明显,Javascript对象只是哈希,而不是从配方中支持的东西,比如预定义的类。
定义之间的区别在于,如果将方法添加到原型,则在内存中只为所有实例创建一个方法。因此,如果您有一个泛型方法和一个在多个实例中创建/使用的对象,您应该将该方法添加到原型。