Шаблон модуля JavaScript - Защищенные участники? - PullRequest
8 голосов
/ 02 января 2012

Алло! Это мой первый вопрос!

Я экспериментирую с шаблоном модуля, предложенным Дагом Крокфордом и другими. Пока что я в основном очень доволен этим, но я немного не уверен в том, как лучше всего справиться с определенной моделью наследования.

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

Но вот мой случай "животных" моих голых костей с помощью предупреждения браузера:

var ZOO = ZOO || {};
//
ZOO.mammal = function () {
   "use strict";
   var voice = "squeak.mp3", // default mammal sound
      utter = function () {
         window.alert(this.voice);
      };
//
   // public interface
   return {
      utter: utter,
      voice: voice
   };
};
//
ZOO.cat = function () {
   "use strict";
   // hook up ancestor
   var thisCat = ZOO.mammal();
   thisCat.voice = "miaw.mp3";
   return thisCat;
};
//
var felix = ZOO.cat();
felix.utter();

Что меня беспокоит в этом подходе, так это то, что мне пришлось сделать voice публичным свойством, чтобы cat мог его изменить.

Что мне действительно нужно, так это что-то вроде «защищенной» видимости (из Java, ActionScript и т. Д.), Так что cat может изменять voice, при этом никто не имеет доступа к felix и не может его изменять.

Есть ли решение?

Ответы [ 3 ]

14 голосов
/ 02 января 2012

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

var ZOO = ZOO || {};

ZOO.mammal = function (protectedInfo) {
   "use strict";
   protectedInfo = protectedInfo || {};
   protectedInfo.voice = "squeak.mp3";

   // public interface
   return {
      utter: function () {
         alert(protectedInfo.voice);
      }
   };
};

ZOO.cat = function () {
   "use strict";

   var protectedInfo = {};
   // hook up ancestor
   var thisCat = ZOO.mammal(protectedInfo);

   protectedInfo.voice = "miaw.mp3";
   return thisCat;
};

Вот демоверсия

1 голос
/ 08 апреля 2015

Существует обходной путь для имитации защищенных участников, когда вы публикуете их на некоторое время, а затем снова приватизируете.Я не большой поклонник этого, но это "решение".

Я просто цитирую из этой статьи SitePoint :

Добавление защищенных членов

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

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

JavaScript не имеет защищенных членов как таковых, но мы можем эффективно создавать их, временно делая данные общедоступными.Для этого позвольте мне сначала познакомить вас с двумя ключевыми функциями - расширением и приватизацией - которые мы определим как часть объекта служебных функций:

var utils = {
  extend : function(root, props) {
    for(var key in props) {
      if(props.hasOwnProperty(key)) {
        root[key] = props[key];
      }
    } return root;
  },
  privatise : function(root, prop) {
    var data = root[prop];
    try { delete root[prop]; } catch(ex) { root[prop] = null; }
    return data;
  }
};

Функция расширения просто добавляет новые свойства вобъект, в то время как функция приватизации копирует свойство, а затем удаляет оригинал.Мы можем использовать расширение в одном модуле, чтобы создать общедоступную ссылку на частную переменную, а затем использовать приватизацию в другом модуле, чтобы скопировать ее обратно в частную переменную и удалить общедоступную ссылку.

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

var MyModule = (function() {
  var myProtectedData = 909;
  var utils = {
    extend : function(root, props) { },
    privatise : function(root, prop) { }
  };
  this.myPublicData = 42;
  return utils.extend(this, { myProtectedData : myProtectedData, utils : utils });
})();

Вы можете видеть, как мы используем вариантшаблон разоблачающего модуля, чтобы возвращать не только открытых членов, но и защищенных членов.Итак, на данный момент у нас есть три открытых члена: MyModule.myProtectedData, MyModule.utils и MyModule.myPublicData.

Теперь вот пример последнего модуля, который использует функцию приватизации для копирования указанных открытых членов обратно в приватныйпеременных, а затем удалите их общедоступные ссылки:

var MyModule = (function() {
  var myProtectedData = this.utils.privatise(this, 'myProtectedData');
  var utils = this.utils.privatise(this, 'utils');
  return this;
}).apply(MyModule);

И как только это будет сделано, защищенные члены заблокированы внутри своих объектов, доступны для обоих модулей, но больше не доступны извне.

Обратите внимание, что функция приватизации полагается на наличие отдельных аргументов для объекта и ключа свойства, поскольку объекты в JavaScript передаются по ссылке.Таким образом, root является ссылкой на MyModule, и когда мы удаляем из него свойство, указанное ключом, мы удаляем это свойство из ссылочного объекта.

Но если это так:

privatise : function(root) {
  var data = root;
  try { delete root; } catch(ex) { root = null; } return data;
}

И вызывается так:

var myProtectedData = this.utils.privatise(this.myProtectedData);

Тогда публичные члены не будут удалены - функция просто удалит ссылку, а не свойство, на которое она ссылается.

Try... конструкция catch также необходима для более старых версий IE, в которых удаление не поддерживается.В этом случае мы аннулируем публичное свойство, а не удаляем его, что, очевидно, не то же самое, но имеет эквивалентный конечный результат отрицания публичной ссылки члена.

1 голос
/ 02 января 2012

Sideteping non-answer:

Есть несколько способов получить защищенные свойства в Javascript, но они не обязательно очень идиоматичны.Если бы я был вами, я бы сначала настоятельно рекомендовал либо

  1. Использование соглашения об общих свойствах с предваряющим подчеркиванием (например: _voice) для обозначения конфиденциальности.Это очень просто и является стандартом среди динамических языков.

  2. Ищите альтернативное решение без наследования.Наследование часто усложняет и соединяет вещи со многими, поэтому старая мантра «предпочитаешь композицию, а не наследование».Javascript имеет много функций, таких как типирование утки и функции более высокого порядка, которые часто позволяют избегать использования наследования в ситуациях, когда оно обычно требуется в Java

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...