Должен ли я использовать прототип или нет? - программирование
Подтвердить что ты не робот

Должен ли я использовать прототип или нет?

Я создаю класс 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);
    };
}
4b9b3361

Ответ 1

Это в точности ситуация с использованием прототипа. Для этого я вижу два основных преимущества:

  • Функции не создаются несколько раз. Если вы определяете функции внутри конструктора, для каждой определяемой вами функции создается всякая анонимная функция при каждом вызове конструктора. Прототипы являются статическими объектами, и каждый экземпляр Vector3D будет просто ссылаться на функции прототипа.
  • Прототип - это единственный объект, с которым можно легко манипулировать. Это дает большую гибкость; к сожалению, я могу лишь привести несколько примеров того, что это может предложить:
    • Если вы хотите создать дочерний класс, например Vector3DSpecial, вы можете просто клонировать Vector3D.prototype и назначать его Vector3DSpecial.prototype. Хотя вы также можете сделать это с помощью конструкторов Vector3DSpecial.prototype = new Vector3D();, конструкторы могут содержать побочные эффекты, которые будут выполняться в этом простом назначении прототипа, и поэтому его следует избегать. С прототипами вы можете даже выбрать только определенные функции в прототипе для копирования в новый класс.
    • Добавление методов в Vector3D - это просто вопрос добавления свойств прототипа и позволяет более легко разделить/упорядочить ваш код на несколько файлов или позволить динамически добавлять методы в другие части кода. Конечно, вы можете сделать комбинацию добавления методов в конструкторе и прототипе, но это противоречиво и, скорее всего, приведет к большей сложности в дальнейшем по пути.

Когда я использовал не прототип? Для одноэлементных объектов, например, контроллер, который взаимодействует со страницей и может делегировать работу другим объектам. Одним из таких примеров является глобальное "уведомление". Здесь расширение маловероятно, и объект создается только один раз, что делает прототип дополнительной (концептуальной) сложностью.

Ответ 2

Прототипные методы будут работать только для общедоступных свойств, если вы будете отслеживать x, y, z как переменные "private", прототип не будет работать.

Я бы использовал последнее, потому что вам могут понадобиться методы, которые работают только с частными/внутренними переменными, но все зависит от контекста.

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

Ответ 3

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