【问题标题】:JavaScript OOP: method definition with or without "prototype"JavaScript OOP:带或不带“原型”的方法定义
【发布时间】:2012-05-17 00:46:36
【问题描述】:

这是代码吗,

function Person() {
    function  myMethod() {
        alert ('hello');
    }
    this.method = myMethod;
}

相当于:

function Person() {    }
Person.prototype.method2  = function() {
    alert ('hello');
};

如果是,我应该使用哪种方法定义以及为什么?

【问题讨论】:

标签: javascript oop methods prototype


【解决方案1】:

不,它们不相等。虽然,它们很相似。第一种方法将为每个创建的new Person() 创建一个新函数myMethod

第二种方法将有一个函数method2,它被所有Person's“共享”。

【讨论】:

    【解决方案2】:

    在您的简单示例中,它们在功能上是等效的,但在幕后的工作方式却大不相同。函数上的prototype 属性实际上是“原型模板”。它说“每当制作一个对象并且我被用作对象的构造函数时,就给他们这个对象作为他们的原型”。

    所以在第二个示例中创建的所有Persons 共享method2 方法的相同副本。

    在第一个示例中,解释器每次遇到function 关键字时,都会创建一个新的函数对象。所以在第一个示例中,Person 的每个实例都有自己的 myMethod 方法副本。绝大多数时候这无关紧要。但是第一种方法使用更多的内存,有时这很重要。

    在更有趣的情况下,它们在功能上并不等效。在第一个示例中,myMethod 可以访问定义在Person 中的局部变量,但第二个示例不能,这是一个区别。

    【讨论】:

    • 您知道第一种方法更有用的案例/上下文吗?谢谢。
    • 第一种情况允许您拥有“私有”变量。 Person 方法中定义的任何局部变量都可以通过myMethod 访问,但不能通过其他方式访问。我建议阅读 Crockford 的 JavaScript the Good Parts,因为他详细介绍了这种模式。
    【解决方案3】:

    在第一个场景中,当您创建一个新人var person1 = new Person(); 时,它将拥有自己的myMethod 副本。如果您创建 100 个 Person 对象,它们每个都有自己的此方法的副本。

    使用原型,每个新的 Person 对象都将共享方法定义。由于该方法只有一个副本,因此内存效率更高。

    如果您打算拥有多个 Person 对象,则第二种方法更好。但如果只有几个 Person 对象,则没那么重要。

    【讨论】:

    • 如果非原型方法变得流行,那么 JavaScript 运行时可能会优化掉差异......
    【解决方案4】:

    它们具有相似的功能,但您应该使用第二种方法(原型),因为当您使用new Person() 创建一个对象时,每个对象都将共享相同的method2,但使用第一种方法,每个新对象都将拥有自己的@ 987654324@会消耗moe内存。

    前几天我问了一个类似的问题,得到了this answer

    【讨论】:

      【解决方案5】:

      不完全等价。

      在这两种情况下,您都在全局命名空间中定义了一个函数(构造函数)Person()

      在第一种情况下,您在 Person() 函数内的闭包中定义了一个新函数 myMethod()。通常,myMethod() 函数在函数/构造函数 Person() 完成后将不可用。但是,在这种情况下,您将其分配给 this.method。因此,当您运行构造函数时

      var myPerson = new Person();
      

      创建一个新对象,然后调用Person() 函数并将this 设置为新对象。因此,您的新对象会收到一个绑定了myMethod 函数的method 字段。

      在第二种情况下,method2Person.prototype 中定义。在这种情况下,当您调用时

      var myPerson = new Person();
      

      在您的新对象中不会直接定义任何字段(因为您在函数Person 中对this 什么都不做)。但是,每个对象都包含对其原型的引用。如果对象是通过调用Person() 创建的,则此引用设置为Person.prototype。因此,您的对象最终将包含method2,尽管不是直接包含在其本身中,而是包含在原型中。所以当你打电话时

      myPerson.method2();
      

      解释器在myPerson对象中查找method2,没有找到,然后查找myPerson的原型,也就是Person.prototype,找到method2,所以调用它。

      长话短说:首先,您的构造函数创建方法,因此每次调用构造函数时,都会创建一个新方法并将其插入到新对象中。在第二种情况下,方法存储在原型中,因此您创建的每个对象都将引用您的方法的同一实例。

      【讨论】:

      • 由于查找,性能方面第一种方法会更快吗?
      • @Jean-PhilippeMartin 是的。您可以获得更快的方法查找,但更多的内存使用。在具有长原型链的重复调用中,性能差异应该是可见的。不过,在这种简单的情况下,可能没什么好担心的。
      • 我这里有一个测试用例来测试方法的性能比较:jsperf.com/method-definition-with-or-without-prototype
      猜你喜欢
      • 2011-06-02
      • 1970-01-01
      • 1970-01-01
      • 2019-02-12
      • 1970-01-01
      • 1970-01-01
      • 2012-03-28
      • 2013-10-02
      • 1970-01-01
      相关资源
      最近更新 更多