我应该使用原型吗?

时间:2011-01-14 12:30:14

标签: javascript

我正在创建一个Vector类,它基本上可以包含三个数值。但是,可以在这样的矢量上进行许多操作 - 例如获得幅度,增加或减去另一个矢量等。

我想知道这些函数是否应该被编码为Vector类的原型函数,或者我应该在构造函数中定义它们。

那么这两种方法中哪一种更可取?

function Vector3D(x, y, z) {
    this.x = x;
    this.y = y
    this.z = z;
}

Vector3D.prototype.magnitude = function() {
    return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
};

function Vector3D(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;

    this.magnitude = function() {
        return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
    };
}

3 个答案:

答案 0 :(得分:50)

这正是使用原型的情况。我认为这样做有两个主要好处:

  1. 多次创建功能。如果在构造函数中定义函数,则会为每个定义的函数创建一个新的匿名函数,每次调用构造函数时都会 。原型是静态对象,Vector3D的每个实例都只是引用原型函数。
  2. 原型是一个易于操作的单个对象。这提供了很大的灵活性;不幸的是,我只能提供一些可以提供的例子:
    1. 如果您想创建一个子类,例如Vector3DSpecial,您只需克隆Vector3D.prototype并将其分配给Vector3DSpecial.prototype即可。虽然您也可以使用Vector3DSpecial.prototype = new Vector3D();构造函数来执行此操作,但构造函数可能包含将在该简单原型赋值中执行的副作用,因此应该避免使用。使用原型,您甚至可以只选择原型中的特定功能复制到新类。
    2. Vector3D添加方法只是向原型添加属性,并允许您的代码更容易拆分/组织成多个文件,或允许动态地在代码的其他部分添加方法。当然,你可以在构造函数和原型中组合添加方法,但这是不一致的,并且可能会导致更多的复杂性。
  3. 我什么时候使用原型?对于单例对象,例如与页面交互并可以将工作委托给其他对象的控制器。全局“通知”对象就是这样一个例子。在这里,扩展不太可能,并且对象仅创建一次,使原型成为额外的(概念上的)复杂性。

答案 1 :(得分:9)

原型方法只适用于公共属性,如果你将x,y,z作为“私有”变量跟踪原型不起作用。

我会使用后者,因为你可能想要只使用私有/内部变量的方法,但这一切都取决于上下文。

function Vector3D(x, y, z) {
   // x, y, z is automatically in this scope now, but as private members.
   this.magnitude = function() {
        return Math.sqrt(x * x + y * y + z *z);
   }
}

答案 2 :(得分:-1)

ECMA 6 http://es6-features.org/#BaseClassAccess

class Shape {
    …
    toString () {
        return `Shape(${this.id})`
    }
}
class Rectangle extends Shape {
    constructor (id, x, y, width, height) {
        super(id, x, y)
        …
    }
    toString () {
        return "Rectangle > " + super.toString()
    }
}
class Circle extends Shape {
    constructor (id, x, y, radius) {
        super(id, x, y)
        …
    }
    toString () {
        return "Circle > " + super.toString()
    }
}

ECMA 5

var Shape = function (id, x, y) {
    …
};
Shape.prototype.toString = function (x, y) {
    return "Shape(" + this.id + ")"
};
var Rectangle = function (id, x, y, width, height) {
    Shape.call(this, id, x, y);
    …
};
Rectangle.prototype.toString = function () {
    return "Rectangle > " + Shape.prototype.toString.call(this);
};
var Circle = function (id, x, y, radius) {
    Shape.call(this, id, x, y);
    …
};
Circle.prototype.toString = function () {
    return "Circle > " + Shape.prototype.toString.call(this);
};