Подтвердить что ты не робот

Закрытие против классов для инкапсуляции?

Я новичок в JS (от С++/etc), и мне просто пришло в голову, что закрытие кажется более простым и удобным способом обработки инкапсуляции, чем классы. Этот код, как представляется, дает простой способ обработки инкапсуляции:

function addProperty(o) {
   var value;

   o["get"] = function()  { return value; }
   o["set"] = function(v) { value = v; }
}

// create two independent objects which are instances of pseudo-class 'addProperty',
// which each have their own version of a set of local fields, and methods that
// operate on those fields:
var a = {};
addProperty(a);
var b = {};
addProperty(b);

Если вы просто хотите, чтобы класс обрабатывал инкапсуляцию (в С++ я нахожу это большую часть времени), есть ли веская причина использовать класс JS вместо закрытия? Вышеприведенный код кажется более интуитивным и компактным, чем классы JS. Нет конструкторов, прототипов или чрезмерного использования 'this'. Вы также получаете то преимущество, что вы должны явно объявлять локальные поля, а не надеяться, что вы не делаете никаких опечаток в своем конструкторе.

ИЗМЕНИТЬ

Хорошо, я просто уточню. Похоже, слово "класс" получает некоторые резервные копии. "Класс", во всяком случае, является расширением концепции типа, а JS не подходит на этом фронте, но я могу делать различные вещи класса с тем, что моя книга (Flanagan) проводит 50 страниц, вызывающих классы. Сортировка.

В любом случае, реальный вопрос заключается в следующем: я использую вкладки jQuery в своем первом веб-приложении. Вчера я заметил, что это не работает, потому что мой JS-код не сохраняет какое-либо личное состояние для каждой вкладки. Когда я переключаюсь между вкладками, динамические/мышиные части моего кода больше не работают должным образом.

Итак, что лучший способ представить частное состояние в приложении? Большая часть кода безопасна, но все, что обрабатывает динамическое поведение, должно каким-то образом инкапсулировать локальное состояние каждой вкладки. С помощью фона С++ явным ответом для меня является создание класса, определяющего динамические части вкладки, и создание экземпляра нового объекта вкладки каждый раз, когда создается вкладка. То, что мне трудно разобраться, заключается в том, действительно ли существуют псевдоклассы JS, или я должен расширить код выше.

Просто прочитайте ссылку на образцы модулей от Джонатана, и теперь мне кажется, что это может быть ответ.

Спасибо.

4b9b3361

Ответ 1

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

Ваши функции get и set тривиально в 20 раз медленнее, чем свойства. У ваших замыканий также есть большие накладные расходы памяти, которые являются O (N) с количеством экземпляров.

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

var AddProperty = {
  constructor: function (v) { this._value = v; return this; },
  get: function () { return this._value; },
  set: function (v) { this._value = v; }
};

var a = Object.create(AddProperty).constructor(1);
var b = Object.create(AddProperty).constructor(2);

Вчера я заметил, что это не работает, потому что мой JS-код не сохраняет какое-либо личное состояние для каждой вкладки.

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

Простое решение состоит в том, чтобы иметь объект за вкладку (или "структуру", если хотите) и сохранить в ней состояние.

Итак, все, что вам нужно сделать, это определить вкладку

var Tab = {
  constructor: function (...) {
    /* init state */
  },
  doTabStuff: function () { /* some method */ },
  ...
}

И затем создайте новые вкладки, когда они вам понадобятся

var tab = Object.create(Tab).constructor(...)

Ответ 2

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

http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

Шаблон модуля предоставляет возможность создания частных членов и методов без каких-либо дополнительных накладных расходов, таких как ease.js:

http://easejs.org/

Ответ 3

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

Во-первых, как комментаторы любят указывать, в javascripts нет никаких реальных классов, мы просто имитируем их закрытием. Здесь, что javascript-учебники называют "class:"

function Class1(){
    var privateState='blah';
    this.get=function(){
        return privateState;
    }
}
var myObj=new Class1();

Важно, что метод get является просто закрытием. Таким образом, это в основном то же, что и ваш код. Поскольку закрытие должно ссылаться на среду, в которой они были созданы (так они могут использовать данные частного внутреннего состояния), они более дороги, чем просто использование публичной функции. Поэтому, если у вас есть статический метод, который не требует внутреннего состояния, вы должны добавить его вместо Class1, используя ключевое слово prototype:

Class1.prototype.staticMethod=function(){...};

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

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