Частная собственность в классах MooTools 1.3+ - PullRequest
5 голосов
/ 24 мая 2011

Последние пару дней я провел, исследуя способ получения приватных или защищенных свойств в классах MooTools. Различные статьи (например, Шон Макартур Получение личных переменных в классе MooTools ) предоставляют подход для устаревших версий MooTools, но я не смог отследить рабочий метод для MooTools 1.3 +.

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

var TestObj = (function() {

 var _privateStaticFunction = function() { }

 return new Class({

  /* closure */
  _privates: (function() {

   return function(key, val) {

    if (typeof(this._data) == 'undefined') this._data = {};

    /* if no key specified, return */
    if (typeof(key) == 'undefined') return;

    /* if no value specified, return _data[key] */
    else if (typeof(val) == 'undefined') {
      if (typeof(this._data[key]) != 'undefined') return this._data[key];
      else return;
    }

    /* if second argument, set _data[key] = value */
    else this._data[key] = val;

   }

  /* tell mootools to hide function */
  })().protect(),

  initialize: function() {},

  get: function(val) { return this._privates(val); },
  set: function(key,val) { this._privates(key,val); }

 })

})();


obj1 = new TestObj();
obj2 = new TestObj();

obj1.set('theseShoes','rule');
obj2.set('theseShoes','suck');

obj1.get('theseShoes') // rule
obj2.get('theseShoes') // suck
obj1._privates('theseShoes') // Error: The method "_privates" cannot be called
obj1._privates._data // undefined
obj1._privates.$constructor._data // undefined

Я очень ценю любые советы! Спасибо всем!

РЕДАКТИРОВАТЬ : Ну, это смущает. Я забыл проверить очевидное, obj1._data. Я не думал, что this будет ссылаться на объект экземпляра! Итак, я отстой. Тем не менее, любые идеи будут великолепны!

1 Ответ

4 голосов
/ 24 мая 2011

хех.в вашем случае более простой паттерн сработает.

рассмотрим переменную за замыканием - очень трудно проколоть.это доступно через геттер и сеттер.

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

var testObj = (function() {
    var data = {__proto__:null}; // 100% private

    return new Class({
        get: function(key) {
            return data[this.uid][key] || null;
        },
        set: function(key, value) {
            data[this.uid][key] = value;
        },
        remove: function(key) {
            delete data[this.uid][key];
        },
        otherMethod: function() {
            alert(this.get("foo"));
        },
        initialize: function() {
            this.uid = String.uniqueID();
            data[this.uid] = {};
        }
    });
})(); // why exec it?


var foo = new testObj();
var bar = new testObj();

foo.set("bar", "banana");
console.log(foo.get("bar")); // banana!
console.log(bar.get("bar")); // undefined.
bar.set("bar", "apple");
console.info(foo.get("bar"), bar.get("bar")); // banana apple

В действии: http://jsfiddle.net/dimitar/dCqR7/1/

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

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

http://jsfiddle.net/dimitar/dCqR7/2/

var testObj = (function() {
    var data = {__proto__:null}; // 100% private

    return new Class({
        get: function(key) {
            return data[key] || null;
        },
        set: function(key, value) {
            data[key] = value;
        },
        remove: function(key) {
            delete data[key];
        },
        otherMethod: function() {
            alert(this.get("foo"));
        }
    });
});


var foo = new new testObj();
var bar = new new testObj();

foo.set("bar", "banana");
console.log(foo.get("bar")); // banana!
console.log(bar.get("bar")); // undefined.
bar.set("bar", "apple");
console.info(foo.get("bar"), bar.get("bar")); // banana apple

edit почему это ...

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

в шаблоне одинВы определяете И запускаете функцию, которая создает прототип и устанавливает data - единственный экземпляр.Затем вы создаете новые функции с этим «живым» прототипом, в котором уже установлено data.

во втором шаблоне создается новый прототип, на который ссылаются для каждого экземпляра, независимо друг от друга.Ваша функция возвращает новую функцию с классом-прототипом ... так что на самом деле new Class({});, следовательно, new new <var>() создаст и создаст экземпляр класса.

, чтобы лучше это понять, возможно, вы можете сначала написать это так - обычнодостаточно шаблона для создания и создания экземпляра класса, который не используется повторно - что будет иметь больше смысла:

new (new Class({
    initialize: function() {
        alert("hi");
    }
}))();

, который, в свою очередь, можно записать так (если он сохранен в переменной):

var foo = new Class({
    initialize: function() {
        alert("hi");
    }
});

new foo();

Надеюсь, это имеет смысл, я не лучший человек, чтобы объяснять ...

...