Частные и привилегированные методы против прототипов

В JavaScript я могу создавать частные и привилегированные методы, объявляя их в конструкторе. Этим я должен вывести их из прототипа объекта. Затем я теряю возможность наследования и некоторую производительность, поскольку каждый объект будет иметь свою собственную копию этих методов вместо обращения к одному объекту прототипа.

Итак, теперь мой вопрос заключается в том, что может быть шаблоном петтер: используйте частные и привилегированные методы или нет. Я не большой поклонник болтаться, поэтому я хочу избежать этого. Итак, что делать?

Каковы ваши впечатления?

Ответ 1

Я никогда не видел никакой ценности при создании так называемых функций 'private' в JavaScript. Просто отметьте их как-то, чтобы указать, что они не являются частью вашего общедоступного API, поэтому клиенты API не гарантируют, что эта функция будет существовать или будет иметь такую ​​же реализацию в будущей версии.

Помимо согласованности API, нет причин не позволять людям просто использовать ваши частные функции, если они этого захотят. Конечно, он позволяет совместным скриптам сжигать ваши личные функции, но эти сценарии, возможно, уже переопределили ваши общедоступные функции API.

Принятый ответ на этот вопрос имеет хорошие комментарии по этому поводу: Частные функции в javascript с расширением имен

Ответ 2

Конвент должен обладать тем, что необходимо... и для частных или защищенных членов psuedo для префикса ваших методов или свойств с помощью подчеркивания.

Я предпочитаю частную/защищенную область psuedo...

var MyObject = (function(){
  var interalStaticVar;

  function ctor(arg1, arg2) {
    //create psuedo-protected context
    this._ = {};

    //create a psuedo-private context
    this.__ = {};

    //stash someval
    this.__.someVal = "hands off";
  }

  ctor.prototype.getSomethingPrivate = function() {
    return this.__.someVal;
  }

  ctor.prototype._doSomethingProtected = function(){ ... }

  ctor.prototype.__doSomethingPrivate = function() { ... }

  return ctor;
}());

Я скажу, что попытка применить парадигмы наследования стиля OO к JavaScript требует неприятностей и, вероятно, означает, что вы делаете что-то неправильно. Я, как правило, придерживаюсь более ТВЕРДОГО дизайна, охватывающего функциональный характер JS в браузере.

Ответ 3

Вы можете эмулировать частные или внутренние методы и свойства, используя

obj._foo = private;

obj.prototype._internalMethod;

Вам нужно отделить свои частные методы от наследования. Все, что можно использовать, не полагаясь на наследование, будет работать нормально. Также шаблон выглядит так:

function construct() { 
    var priv;

    this.someValue = foo;
    this.someMethod = function() { }
}

Здесь мы игнорируем прототип и напрямую записываем объект. Этот шаблон, основанный на замыканиях, чтобы скрыть методы и переменные, хорошо работает с mixins.

Беспокойство о том, неэффективны ли методы повторного использования в конструкторе, - это микро оптимизация и зло. Если вы не ожидаете создать не менее 1000 объектов, разница будет пренебрежимой.

Ответ 4

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

В этом случае одним из вариантов было бы просто сохранить их как свойство в конструкторе. Затем, когда вы вызываете их в конструкторе, вы должны использовать метод .call() для установки контекста для текущего объекта.

Таким образом, вы автоматически получаете доступ к открытым членам через this и к приватным переменным, если вы передаете их в качестве аргумента.

var myClass = function() {
    this.someprop = 'prop value';
    var privVar = 'private value';

    myClass.func.call(this, privVar);
};

myClass.func = function(priv){ 
    alert(this.someprop);
    alert(priv); 
};

var inst = new myClass;

Таким образом, это просто использует функцию MyClass в качестве хранилища пространства имен для функции, которая используется конструктором. Конструктор вызывает его из контекста this, который выполняет что-то с this.someProperty и privVar, которые передаются.

Не уверен, что это то, что вам нужно, но это один из вариантов.


Как правильно отмечено @Raynos в комментариях ниже, любые свойства, добавленные в конструктор MyClass в качестве простого хранилища пространства имен, вообще не являются частными и могут быть доступ через любой код, который может получить доступ к конструктору.

Вы можете сделать некоторую проверку, чтобы убедиться, что она вызвана должным образом, например добавление проверки instanceof, чтобы убедиться, что она вызывается из экземпляра MyClass, но такие проверки не являются абсолютно безопасными и не предлагают защита фактических частных членов.

Ответ 5

Я думаю, все зависит от того, как вы хотите использовать свои объекты. Если вам нужны частные переменные/функции в каком-либо объекте и хотите, чтобы они были доступны с помощью методов прототипа этого объекта, вы должны объявить прототипы методов внутри конструктора (см. пример здесь).

По-моему, это сводится к разработке и использованию программы. Если вам нужны объекты с действительно частными переменными или - функциями, спроектируйте его как пример, который я дал, иначе нет. По моему опыту частные/привилегированные функции не влияют на производительность.

Ответ 6

Я обычно следую следующему шаблону при создании объектов javascript.

var builders = (function() {
var privateMethod = null;
function builders() {
            this.a_priviledged_method = function() {};
            this.pointerToPrototypeMethod = __bind(this.prototypeMethod, this);
    }
    builders.prototype.prototypeMethod = function(){};
    return builders;
})();
// general method to bind a function call to a context
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

Примечание:

  • 'privateMethod' не является приватным в том смысле, что он не находится внутри конструктора, но, просматривая его, можно сделать его закрытым для каждого экземпляра создателей, которые будут созданы.
  • чтобы убедиться, что прототипные методы вызывают в контексте, в котором они созданы, а не в контексте, в котором они называются. Я создал псевдо-привилегированный метод, который использует метод прототипа с контекстом во время создания. Последующие обращения к прототипным методам всегда будут выполняться в контексте во время создания.
  • Поскольку механизм поиска метода javascript определяет, что цепочка прототипов должна быть проверена последним, поэтому "pointerToPrototypeMethod" будет "обнаружен" перед "prototypeMethod".
  • Можно было бы реализовать "pointerToPrototypeMethod", аналогичный "a_priviledged_method", но в этом случае каждый экземпляр "строителей" имел бы свою собственную копию привилегированного метода, ведущего к копированию кода.
  • При вызове частного метода следует убедиться, что он должен быть вызван путем предоставления контекста. Например: в теле "a_priviledged_method", если вы хотите вызвать "privateMethod", тогда его нельзя вызывать как privateMethod(), но его следует вызывать как privateMethod.apply(это, args). Преимущество состоит в том, что если вы хотите вызвать привилегированный метод из приватного метода, то он будет в том же контексте (к которому был вызван частный метод).

Надеюсь, что это поможет.

Ответ 7

(function () {
    function privateFunc () { ... }

    A.prototype.publicFunc1 = function () { ... };
    A.prototype.publicFunc2 = function () { ... };

})();

function A () { ... }

I Edit: Это не поможет, если вы также хотите использовать частные переменные.