【问题标题】:Adding methods to custom objects in Javascript [duplicate]在Javascript中向自定义对象添加方法[重复]
【发布时间】:2011-09-10 16:41:40
【问题描述】:

可能重复:
Use of 'prototype' vs. 'this' in Javascript?

我去了各种网站,但无法理解以下向自定义对象添加方法的方式之间的区别:

方法一:

function circle(radius){
     this.radius = radius;
     this.area = function(){ return 3.14*this.radius*this.radius;}
}

方法二:

function circle(radius){
     this.radius = radius;
}
circle.prototype.area = function(){ return 3.14*this.radius*this.radius; }

是否存在其中一种方法存在而另一种方法没有的性能或设计问题?

【问题讨论】:

标签: javascript prototype-programming


【解决方案1】:

这里是一种查看差异的方法:

var circle1 = circle(1);
var circle2 = circle(1);
alert(circle1.area == circle2.area);

对于 Method1,您将看到 false,而 Method2 在 true 中产生。这是因为在第一种情况下,您为每个创建的对象分配一个新的闭包函数,即使两个对象做同样的事情,两个对象最终也会有不同的area 函数。在第二种情况下,对象与其area 方法共享同一个原型对象,该方法在两种情况下当然是相同的。

由于以下几个原因,通常方法 2 更可取:

  1. 对象创建速度更快,因为只需要初始化自定义属性。
  2. 实例化同一事物的多个副本不会浪费内存。
  3. 您可以通过调用Object.hasOwnProperty 轻松找出哪些对象属性具有自定义值。

还有一些缺点需要牢记。

  1. 即使您从未创建任何对象,您也总是会花时间设置原型。
  2. 属性访问稍慢,因为 JavaScript 引擎需要先检查对象属性,然后检查原型对象的属性(不过,现代 JavaScript 引擎对此进行了很好的优化)。
  3. 在原型上放置对象或数组是一个常见的陷阱,它们将在所有对象实例之间共享。

这是一个常见错误的例子:

function NumberCollection()
{
}
NumberCollection.prototype = {
    numbers: [],
    sum: function()
    {
        var result = 0;
        for (var i = 0; i < this.numbers.length; i++)
            result += this.numbers[i];
        return result;
    }
}

var c1 = new NumberCollection();
c1.numbers.push(5);
alert(c1.sum());   // Shows 5
var c2 = new NumberCollection();
c2.numbers.push(6);
alert(c2.sum());   // Oops, shows 11 because c1.numbers and c2.numbers is the same

这里的正确方法是:

function NumberCollection()
{
    this.numbers = [];
}
NumberCollection.prototype = {
    numbers: null,
    sum: function()
    {
        var result = 0;
        for (var i = 0; i < this.numbers.length; i++)
            result += this.numbers[i];
        return result;
    }
}

【讨论】:

  • 感谢您的详细解释...您的意思是一般来说,必须使用原型属性声明要在所有实例之间共享的函数,并且必须在对象中声明属性.
  • 不仅仅是功能。属性的初始值也应该在原型上声明——如果所有对象实例都应该有一个属性obj.type == 4,除非显式更改,那么在原型上声明type: 4而不是每次都在构造函数中分配这个值是最有意义的。但是,正如我所说,您应该小心在原型中分配非原始类型(对象或数组),因为这些是可以更改的,您可能不希望这些更改影响所有对象实例。
【解决方案2】:

第一种方法(我们称之为类型 1)将area() 函数添加到对象本身。每次使用new 构造circle 对象时,其主体都会复制 (!) 到新实例。

第二种方法(类型 2)将area() 函数添加到对象原型(原型在层次结构中“上一级”)。每次创建 circle 的新实例时,只会复制 radius 属性。

现在,当您在第二个对象的实例上调用 area() 时,JavaScript 无法在对象本身上找到该函数。现在它“上升”原型链并使用它找到的该名称的第一个函数。

现在这有几个含义:

  1. 新对象实例会更小(更少的物理代码)
  2. 您可以立即为所有类型 2 的现有对象更改 area 的实现,而当它们存在时(通过更改原型),您不能对类型 1 执行此操作李>
  3. 您可以在类型 2 的单个实例中覆盖 area 的功能,同时保留该函数的“原始实现”

【讨论】:

  • cw'd 因为这个问题会因为重复而被关闭。
猜你喜欢
  • 2011-06-09
  • 2014-10-24
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-11
  • 1970-01-01
相关资源
最近更新 更多