Javascript 使用原型相对于直接在构造函数中定义方法的优势?
我想知道使用其中任何一种方法是否比使用另一种方法有任何优势,我应该走哪条路 建造商方法:Javascript 使用原型相对于直接在构造函数中定义方法的优势?,javascript,oop,prototype,Javascript,Oop,Prototype,我想知道使用其中任何一种方法是否比使用另一种方法有任何优势,我应该走哪条路 建造商方法: 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 =
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 () {
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 () {}
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
// 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!"); }
请注意如何更改应用于这两个实例的方法?这是因为ins1
和ins2
共享相同的calc()
函数。为了在构造过程中创建公共方法,必须将新方法分配给已创建的每个实例,这是一项棘手的任务。这是因为ins1
和ins2
将拥有各自单独创建的calc()
函数
在构造函数内部创建方法的另一个副作用是性能较差。每次构造函数运行时都必须创建每个方法。原型链上的方法创建一次,然后由每个实例“继承”。另一方面,公共方法可以访问“私有”变量,这在继承方法中是不可能的
至于你的function Class(){}
vsvar Class=function(){}
问题,前者在执行之前被“提升”到当前作用域的顶部。对于后者,将挂起变量声明,但不挂起赋值。例如:
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
// 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!"); }
原型方法的优点是效率。所有
Class
对象(我指的是通过调用Class
构造函数创建的对象)之间共享一个calc()
函数对象。另一种方法(在构造函数中分配方法)为每个类
对象创建一个新的函数对象,在调用类
构造函数时使用更多内存并花费更多的处理时间。但是,这种方法确实有一个优点: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(){…}
的比较,我通常更喜欢后者,因为这意味着函数有一个名称,在调试时可能很有用。另一个区别是后一个版本(函数声明)被提升,这意味着它在定义它的范围内的任何地方都可用,而不仅仅是在定义之后。但是,我们更愿意在任何地方使用前者(函数表达式)
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);
};
原型方法的优点:
啊,这让事情变得更清楚了:)我没有意识到效率的不同——知道这一点非常有用。提升效果也是如此——确实很棘手。谢谢你这么好的回答,我从中学到了很多!非常古老的问题,但不知何故,它遵循了一个链接并在这里绊倒了——我认为如果你保持论点的数量一致,这个例子会更有说服力(只是为了证明它使用的是
a+b
。这确实是一个小问题,但它可以帮助读者识别您所关注的差异,并排除他可能正在阅读的其他因素(例如:如果您有第三个参数,第一次调用会发生什么情况)。这个例子很简单,希望程序员足够优秀,不会被小的差异所困扰。当然,使用函数模式也可以达到同样的效果,从而避免模仿经典语言的继承模式。这部分代码在做什么:Class.prototype.calc=function(){var args=Array.prototype.slice.apply(arguments),res=0,c;
由于一段时间过去了,我们现在有了ES6+,我想指出,arrow函数定义是var Class=function(){…}的缩写
,因此也没有被提升。谢谢你的回答,我很感激,现在我更加意识到资源堆栈溢出是多么伟大。您好,您所说的继承类是什么意思?我认为这不是正确的术语,因为javascript没有类的概念。当您说派生类的重写方法时,您是指另一个对象,谁的原型是你的对象?我迷路了。你能编辑或解释一下吗?Alexandr你能用一个例子解释一下#2吗?蒂姆,也谢谢你的回答!ReClass=function(){…}
,即在全局/窗口范围内定义,就名称而言,我对这种方法没有任何调试问题,尽管可以理解,这种方法似乎没有出现任何问题。不确定这种方法与您的两种方法之间是否有任何其他区别。@NickWiggill:自从我写这篇answe之后,内置浏览器开发工具已经取得了长足的进步r,他们现在在从上下文推断合适的函数名方面做得更好了,所以我同意,现在调试的容易程度已经不再是一个问题。进行了js Perf测试以可视化性能差异。@DaveVoyles: