Приватные и привилегированные методы против методов-прототипов - PullRequest
10 голосов
/ 30 января 2011

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

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

Какие у вас впечатления?

Ответы [ 7 ]

5 голосов
/ 30 января 2011

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

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

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

4 голосов
/ 30 января 2011

Соглашение будет заключаться в том, чтобы охватить то, что необходимо ... и для частных или защищенных членов 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 голосов
/ 30 января 2011

Я просто собираюсь предположить, что у вас есть некоторые функции, которые используются в конструкторе, но не являются частью общедоступного 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, но такие проверки совсем не безопасны и не предлагают защита реальных частных членов.

3 голосов
/ 30 января 2011

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

obj._foo = private;

obj.prototype._internalMethod;

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

function construct() { 
    var priv;

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

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

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

2 голосов
/ 30 января 2011

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

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

0 голосов
/ 01 июля 2013

Я обычно придерживаюсь следующего шаблона при создании объектов 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); }; };

Примечания:

  1. 'privateMethod' не является приватным в том смысле, что он не находится внутри конструктора, но, ограничивая его, можно сделать его приватным для каждого экземпляра создателей, которые будут созданы.
  2. чтобы убедиться, что прототипные методы вызываются в контексте, в котором «они созданы», а не в контексте, «в котором они вызываются». Я создал псевдо-привилегированный метод, который является методом прототипа с контекстом во время создания. Последующие вызовы прототипных методов всегда будут происходить в контексте во время создания.
  3. Поскольку механизм поиска методов в javascript требует, чтобы цепочка прототипов проверялась последней, следовательно, 'pointerToPrototypeMethod' будет 'обнаружен' перед 'prototypeMethod'.
  4. Можно было бы реализовать 'pointerToPrototypeMethod', похожий на 'a_priviledged_method', но в этом случае каждый экземпляр 'builders' имел бы свою собственную копию привилегированного метода, что привело бы к копированию кода.
  5. При вызове приватного метода нужно убедиться, что он вызывается, предоставив контекст. Например, в теле «a_priviledged_method», если кто-то хочет вызвать «privateMethod», он не должен вызываться как privateMethod (), а должен называться privateMethod.apply (this, args). Преимущество состоит в том, что если кто-то хочет вызвать привилегированный метод из частного метода, он будет в том же контексте (к которому был вызван частный метод).

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

0 голосов
/ 30 января 2011
(function () {
    function privateFunc () { ... }

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

})();

function A () { ... }

I Edit: это не поможет, если вам также нужны приватные переменные.

...