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

Leo*_*Leo 293 javascript oop prototype

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

构造方法:

var Class = function () {

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

};
Run Code Online (Sandbox Code Playgroud)

原型方法:

var Class = function () {};

Class.prototype.calc = function (a, b) {
    return a + b;
};
Run Code Online (Sandbox Code Playgroud)

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

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

var Class = function () {};
Run Code Online (Sandbox Code Playgroud)

VS

function Class () {};
Run Code Online (Sandbox Code Playgroud)

谢谢!

And*_*y E 450

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

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
Run Code Online (Sandbox Code Playgroud)

请注意如何更改应用于两个实例的方法?这是因为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!"); }
Run Code Online (Sandbox Code Playgroud)

  • Aah,这让事情变得更加清晰:)我没有意识到效率的差异 - 这一点非常有用.同样的提升效果 - 确实很棘手.多亏了这么好的答案,我从中学到了很多东西! (33认同)
  • 很老的问题,但不知怎的,一个链接,并在这里偶然发现 - 我认为这个例子会更有说服力,如果你保持参数的数量一致(只是为了证明它使用的是'a + b`.这真的是一个小点,但它有助于读者识别你所关注的差异以及排除他可能正在阅读的其他因素(例如:*如果你确实有第三个参数,那么第一次调用会发生什么*).这个例子很简单足够的,希望程序员足够好,不要陷入微小的差异. (5认同)

Tim*_*own 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;
    };
};
Run Code Online (Sandbox Code Playgroud)

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

  • 制作了一个js Perf测试来可视化性能差异.http://jsperf.com/class-comparison (3认同)
  • @NickWiggill:自从我编写这个答案以来,内置的浏览器开发人员工具已经走过了漫长的道路,他们现在可以更好地从上下文中推断出合适的函数名称,所以我同意调试的简易性不是很重要这些日子. (2认同)

Ale*_*ndr 43

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);  
};
Run Code Online (Sandbox Code Playgroud)

原型方法的优点:

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

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

  • 感谢您的回答,我很感激,现在更加意识到 StackOverflow 是一个多么棒的资源。 (2认同)