Javascript 使用原型与直接在构造函数中定义方法的优点?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4508313/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 12:41:49  来源:igfitidea点击:

Advantages of using prototype, vs defining methods straight in the constructor?

javascriptoopprototype

提问by Leo

I am wondering if there are any advantages of using any of these over the other, and which way should I go?

我想知道使用这些中的任何一个是否有任何优势,我应该走哪条路?

Constructor approach:

构造方法:

var Class = function () {

    this.calc = function (a, b) {
        return a + b;
    };

};

Prototype approach:

原型方法:

var Class = function () {};

Class.prototype.calc = function (a, b) {
    return a + b;
};

I don't like that, using the prototype, method definitions are separated from the class, and I'm not aware if there is any specific reason I should use this over just the first approach.

我不喜欢那样,使用原型,方法定义与类分开,我不知道是否有任何特定原因我应该在第一种方法上使用它。

Also, is there any benefit of using a function literal to define a "class", over just function definition:

此外,使用函数文字来定义“类”是否有任何好处,而不仅仅是函数定义:

var Class = function () {};

vs

对比

function Class () {};

Thanks!

谢谢!

回答by Andy E

Methods that inherit via the prototype chain can be changed universally for all instances, for example:

通过原型链继承的方法可以对所有实例进行通用更改,例如:

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

Notice how changing the method applied to both instances? This is because ins1and ins2share the same calc()function. In order to do this with public methods created during construction, you'd have to assign the new method to each instance that has been created, which is an awkward task. This is because ins1and ins2would have their own, individually created calc()functions.

请注意如何更改应用于两个实例的方法?这是因为ins1ins2共享相同的calc()功能。为了使用在构造期间创建的公共方法执行此操作,您必须将新方法分配给已创建的每个实例,这是一项笨拙的任务。这是因为ins1并且ins2会有自己的、单独创建的calc()函数。

Another side effect of creating methods inside the constructor is poorer performance. Each method has to be created every time the constructor function runs. Methods on the prototype chain are created once and then "inherited" by each instance. On the flip side of the coin, public methods have access to "private" variables, which isn't possible with inherited methods.

在构造函数中创建方法的另一个副作用是性能较差。每次构造函数运行时都必须创建每个方法。原型链上的方法创建一次,然后由每个实例“继承”。另一方面,公共方法可以访问“私有”变量,这是继承方法无法实现的。

As for your function Class() {}vs var Class = function () {}question, the former is "hoisted" to the top of the current scope before execution. For the latter, the variable declaration is hoisted, but not the assignment. For example:

至于你的function Class() {}vsvar 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!"); }

回答by Tim Down

The advantage of the prototype approach is efficiency. There is one calc()function object shared between all Classobjects (by which I mean objects created by calling the Classconstructor). The other way (assigning methods within the constructor) creates a new function object for every Classobject, using more memory and taking more processing time when calling the Classconstructor. However, this approach does have an advantage: the calc()method has access to local variables within the constructor, which you can use to your advantage:

原型方法的优点是效率。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;
    };
};

Regarding var Class = function() {...}versus function Class() {...}, I generally prefer the latter is because it means the function has a name, which can be useful when debugging. The other difference is that the latter version (a function declaration) is hoisted, meaning that it is available everywhere within the scope in which it is defined, not just after the definition. However, some peopleprefer to use the former (a function expression) everywhere.

关于var Class = function() {...}vs function Class() {...},我通常更喜欢后者,因为它意味着函数有一个名称,这在调试时很有用。另一个区别是后一个版本(函数声明)被提升,这意味着它在定义它的范围内的任何地方都可用,而不仅仅是在定义之后。但是,有些人更喜欢在任何地方使用前者(函数表达式)。

回答by Alexandr

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);  
};

Advantages of prototype methods:

原型方法的优点:

  1. When you define methods via prototype, they are shared among all YourClass instances. As a result the total size of such instances is < than if you define methods in constructor; There are tests that show how method definition via prototype decrease the total size of html page and as a result a speed of its loading.

  2. another advantage of methods, defined via prototype - is when you use inherited classes, you may override such methods and in the overriden method of the derived class you may invoke the method of base class with the same name, but with methods defined in constructor, you cannot do this.

  1. 当您通过原型定义方法时,它们在所有 YourClass 实例之间共享。因此,如果您在构造函数中定义方法,则此类实例的总大小小于;有一些测试显示通过原型定义方法如何减少 html 页面的总大小,从而降低其加载速度。

  2. 通过原型定义的方法的另一个优点是,当您使用继承的类时,您可以覆盖这些方法,并且在派生类的覆盖方法中,您可以调用具有相同名称的基类方法,但使用在构造函数中定义的方法,你不可以做这个。