我想知道使用这些方法相对于其他方法是否有优势,我应该走哪条路?
构造方法:
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 () {};
谢谢!
#1 楼
通过原型链继承的方法可以在所有实例中通用更改,例如: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() {}
与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!"); }
评论
啊,这让事情变得更加清楚了:)我没有意识到效率的差异-了解这一点非常有用。提升效果也一样-确实很棘手。谢谢您这么好的回答,我从中学到了很多!
–狮子座
2010-12-22 11:09
一个非常老的问题,但是以某种方式跟随了一个链接,并在这里迷迷糊糊-我认为该示例将更多地表明您是否保持参数数量一致(只是为了证明它使用的是a + b。这确实是一个小问题,但是帮助读者识别您正在关注的差异,并排除他可能正在阅读的其他因素(例如:如果您有第三个参数,则在第一次调用中会发生什么)。这个例子很简单,希望程序员足够好,不会被小差异困扰。
–vol7ron
2014年4月3日14:43
当然,使用功能模式可以实现相同的效果,从而避免了模仿经典语言的继承模式。
– timebandit
15年4月15日在10:44
代码的这部分内容是做什么的:Class.prototype.calc = function(){var args = Array.prototype.slice.apply(arguments),res = 0,c;
– Jwan622
17-10-31在3:12
由于已经过去了一段时间,现在我们有了ES6 +,我想指出,箭头函数定义是var Class = function(){...}的简写,因此也无法使用。
–乔纳森·赖斯(Jonathan Rys)
18年4月19日在19:39
#2 楼
原型方法的优点是效率。在所有calc()
对象之间共享一个Class
函数对象(我的意思是通过调用Class
构造函数创建的对象)。另一种方法(在构造函数中分配方法)为每个Class
对象创建一个新的函数对象,在调用Class
构造函数时使用更多的内存并占用更多的处理时间。但是,这种方法确实有一个优势:calc()
方法可以访问构造函数中的局部变量,您可以利用它来发挥自己的优势: ,我通常更喜欢后者,因为它意味着该函数具有名称,这在调试时很有用。另一个不同之处是,悬挂了后一个版本(函数声明),这意味着它在定义它的范围内的任何地方都可用,而不仅仅是在定义之后。但是,有些人更喜欢在各处使用前者(函数表达式)。评论
蒂姆,也感谢您的回答,谢谢!
–狮子座
2010-12-22 11:20
Re Class = function(){...},即在全局/窗口范围内进行定义,尽管可以理解的是吊装似乎没有发生,但是在名称方面我没有任何调试问题。不知道这种方法与您的两种方法之间是否还有其他区别。
–工程师
2014年7月27日在17:05
@NickWiggill:自从我编写此答案以来,内置的浏览器开发人员工具已经走了很长一段路,现在它们可以更好地从上下文中推断出合适的函数名称,因此,我同意调试的便利性不再是一个问题这些日子。
– Tim Down
2014年7月27日在19:05
进行了JS Perf测试以可视化性能差异。 jsperf.com/class-comparison
–伯恩哈德
2015年2月10日在9:52
@DaveVoyles:或者实际上是这篇文章:stackoverflow.com/questions/9772307/…
– Tim Down
15年9月28日在8:32
#3 楼
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实例之间共享。因此,与在构造函数中定义方法相比,此类实例的总大小为<;有测试显示了通过原型进行方法定义如何减少html页面的总大小并因此加快了html页面的加载速度。
通过原型定义的方法的另一个优势-当您使用继承的类时,您可以覆盖这样的方法以及在派生类的重写方法中,您可以使用相同的名称调用基类的方法,但对于在构造函数中定义的方法,则不能执行此操作。
评论
感谢您的回答,我非常感激,现在更加意识到StackOverflow资源有多大。
–狮子座
2010-12-22 11:20
您好,继承类是什么意思?我认为这不是正确的术语,因为javascript没有类的概念。当您说派生类的重写方法时,您的意思是另一个对象,该对象的原型是您的对象吗?我迷路了。您能编辑还是解释?
–人
16年5月5日在6:15
亚历山大,您可以举一个例子来解释第二条吗?
– Govind Rai
17年1月16日在20:04
评论
简而言之:您将节省内存。