Функции прототипа JavaScript с использованием привилегированных функций получения/установки?

Вопрос из трех частей:

  1. Есть ли смысл добавлять второй уровень абстракции и использовать функцию получения/установки прототипа для вызова функций получения/установки привилегированного конструктора? См. ns.Wheel.prototype.getWeight2() и ns.Wheel.prototype.setWeight2() ниже.

  2. Вызов swiss.getWeight() вызывает метод this.getWeight() в конструкторе. Любой способ переместиться на один уровень вверх по цепочке прототипов, чтобы вместо этого вызвать ns.Wheel.prototype.getWeight()?

  3. Любое значение для «скрытия» функций получения/установки прототипа «позади» конструктора получения/установки? Например, ns.Wheel.prototype.getWeight() "спрятан" за методом this.getWeight() в конструкторе.

Также обратите внимание, как геттер/сеттер прототипа добавляет единицу измерения для граммов; т. е. единица «г». Например, this.getWeight возвращает 1000, а ns.Wheel.prototype.getWeight возвращает 1000 г.

В этом примере используются колеса швейцарского сыра.

(function(ns) {
    ns.Wheel = function() {
        var _weight = 1000; // weight of cheese wheel. Private variable.
        this.getWeight = function() { return _weight } // privileged weight getter
        this.setWeight = function(weight) { return _weight = weight } // privileged weight setter
    }
    ns.Wheel.prototype.getWeight = function() { return this.getWeight()+'g' }
    ns.Wheel.prototype.setWeight = function(weight) { return this.setWeight(weight)+'g' }
    ns.Wheel.prototype.getWeight2 = function() { return this.getWeight()+'g' }
    ns.Wheel.prototype.setWeight2 = function(weight) { return this.setWeight(weight)+'g' }
})(window.cheese = window.cheese || {});  // immediate function namespacing technique

var swiss = new cheese.Wheel();
console.log(swiss.getWeight()); //-> 1000. Invokes constructor method
console.log(swiss.setWeight(2000)); //-> 2000. Invokes constructor method
console.log(swiss._weight); //-> undefined. Private variable!!!
console.log(swiss.getWeight2()); //-> 2000g. Invokes prototype method.
console.log(swiss.setWeight2(9000)); //->9000g. Invokes prototype method.

person kmiklas    schedule 16.12.2013    source источник
comment
Я бы порекомендовал взглянуть на prototype.js и его действительно хорошее поведение наследования используя Class.create и $super() для ваших целей. А теперь побейте меня камнями за реанимацию такой злой старой библиотеки, друзья! ;)   -  person RienNeVaPlu͢s    schedule 17.12.2013
comment
Я бы рекомендовал не беспокоиться о том, чтобы сделать переменные закрытыми в JS. Чтобы иметь закрытые переменные, вы должны переместить методы, которые их используют, в свой конструктор, а это означает, что у вас есть копия каждого нестатического метода в вашем конструкторе. Это пустая трата памяти. Общепринятое соглашение состоит в том, чтобы называть частные переменные символами подчеркивания, а затем просто никогда не использовать переменные с префиксами подчеркивания вне контекста, в котором они были созданы. Если вам действительно нужны приваты, рассмотрите возможность использования TypeScript, который делает то, что я предложил, но выполняет проверки во время компиляции.   -  person John Kurlak    schedule 17.12.2013
comment
Я согласен с комментариями не использовать закрытие для частных членов и привилегированных методов, но если вам действительно нужно это сделать, то этот шаблон может быть полезен: stackoverflow.com/a/19879651/1641941 Это не мешает вам полностью получать доступ к частным значениям, но если у вас много частных значений, это уменьшит количество членов вашего объекта с именем _somePrivate   -  person HMR    schedule 17.12.2013


Ответы (2)


  1. #P1#
    #P2#
  2. #P3#
    #P4# #P5#
  3. #P6#
    #P7# #P8#
    function Egg(color) {
        if(color == "invisible") {
            this.examine = function() { return "You can't see the egg at all! }
        } 
    }
    
    Egg.prototype.examine = function() { return "The egg is painted " + color; }
    
    #P9#

Я решительно поддерживаю второй комментарий выше, в котором вообще не рекомендуется использовать частные переменные. Они тратят память, как описано в моем первом пункте, требуя, чтобы метод, который их использует, был определен для каждого экземпляра. Пытаясь имитировать частные переменные, вы растрачиваете мощь прототипного наследования. Вместо этого (как упоминалось в комментариях) сделайте все свои переменные общедоступными и обозначьте свои «частные» переменные знаком подчеркивания.

person apsillers    schedule 16.12.2013
comment
1. Согласен... 2. Вот что такое this.getWeight() и this.setWeight... 3. Это мой вопрос №2: как я могу позволить Метод прототипа просвечивает? Спасибо за ответ :^) - person kmiklas; 17.12.2013
comment
@kmiklas Я неправильно понял ваш пункт № 2; Я много редактировал. - person apsillers; 17.12.2013

Есть ли смысл добавлять второй уровень абстракции и использовать функцию получения/установки прототипа для вызова функций получения/установки привилегированного конструктора? См. ns.Wheel.prototype.getWeight2() и ns.Wheel.prototype.setWeight2() ниже.

Почему бы нет? Что ж, имейте в виду, что вызов функций стоит дорого, поэтому, если вы просто добавляете 'g' в конце, вы можете сделать это вручную, если хотите выиграть несколько микросекунд.

Вызов swiss.getWeight() вызывает метод this.getWeight() в конструкторе. Любой способ переместиться на один уровень вверх по цепочке прототипов, чтобы вместо этого вызвать ns.Wheel.prototype.getWeight()?

Да, ты можешь:

  • Используйте разные имена
  • Используйте cheese.Wheel.prototype.getWeight.call(swiss)

Любое значение для «скрытия» функций получения/установки прототипа «позади» конструктора получения/установки? Например, ns.Wheel.prototype.getWeight() «спрятан» за методом this.getWeight() в конструкторе.

Это зависит от ситуации. В вашем случае я бы использовал разные имена, чтобы не «прятаться».

person Oriol    schedule 16.12.2013
comment
Пространство имен — это сыр, поэтому второй пункт выше на самом деле — это cheese.Wheel.prototype.getWeight.call(swiss), но ХОРОШО!!! тывм! - person kmiklas; 17.12.2013
comment
@kmiklas Верно, исправлено. - person Oriol; 17.12.2013