Действительно частная переменные JavaScript


Я создал функцию, которая, я считаю, по-настоящему приватным переменным. Это не совсем готов по нескольким причинам:

  • Он использует объект.defineProperty - я могу справиться с этим
  • Это повторное определение каждой функции в прототипе, выполняя функцию eval( ФН.метод toString() ) -- я не такой
  • Я повторно определение прототипов, поэтому делаю с преимуществом прототипы! -- дело выключатель

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

function foo(){
    this.definePrivateProperties('foo', 'bar');
}

foo.prototype.setFoo = function(x){
    this.foo = x;
};

foo.prototype.getFoo = function(){
    return this.foo;
};

foo.prototype.definePrivateProperties = function(){
    var   self = this,
          args = arguments,
      validFns = {},
         proto = this.__proto__;

    // replace all functions in prototype with new ones!
    // set a random key on each new function
    //   (not 100% secure, but close enough for now)
    //   this ensures that the function is unique to -this- object
    for(var fn in proto){
        this[ fn ] = eval( '(' + proto[fn] + ')' );
        validFns[ this[ fn ].key = Math.random() ] = 1;
    }

    for(var i=0, l=args.length; i<l; i++){
        (function(){
            var val;

            Object.defineProperty(self, args[i], {
                get          : function getter(){
                    if(validFns[ arguments.callee.caller.key ])
                        return val;
                },
                set          : function setter(v){
                    if(validFns[ arguments.callee.caller.key ])
                        val = v;
                },
                configurable : true,
                enumerable   : false
            });
        })();
    }
};

> var x = new foo();
> x.setFoo(42);
> x.foo = 20;
20
> x.foo;
undefined
> x.getFoo();
42


948
6
задан 7 июля 2011 в 01:07 Источник Поделиться
Комментарии
3 ответа

Что касается кода:


  • Свойство геттер и сеттер, вероятно, следует выбросить исключение, если проверка в отношении звонившего не удалось. Если вы попытаетесь установить его в любой функции, кроме одной, определенной на прототип, вы не хотите это просто сбой, если это произойдет, вы будете тратить много времени, пытаясь выяснить, почему ваши изменения не торчит. (Особенно в свете другие вопросы ниже.)

  • Если вы собираетесь назначить другую клавишу для каждой функции-члена, Вы могли бы рассмотреть вопрос о внесении validFns[ключ] быть функция с ключом, а не просто '1', так что вы можете проверить его против звонящего. (Обеспечивает ключ не случайно совпадают.)

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

  • Способ проверки доступа теперь только функции-члены использовать их. Хотя это может быть целью, это больше калечит, чем это звучит.

Наблюдать:

foo.prototype.doStuff = function() {
var self = this;
$('input.some_selector').each(function() {
self.foo += parseInt(this.value);
});
};

Мы в частной функции, которая должна иметь доступ к ФОО. Но поскольку фактический доступ в анонимную функцию, а не doStuff, это не допускается. Для того, чтобы это исправить (а исправить это вы должны), то ваша регистрация доступ должен идти вниз по стеку вызовов (регистрация абонента, затем звонящего абонента, и так далее), пока не найдет функцию с помощью ключа. Рекурсивные функции, кажется, что такого поиска огромное количество неприятностей, хотя предельную глубину может помочь.


  • definePrivateProperties можно запустить второй раз. А третий, четвертый и т. д. И каждый раз, когда вы называете его, он стирает значение предыдущее свойство, чтобы добавить новый. Читайте: внешний код может испортить ваш собственный переменных.

Сказать:

foo.prototype.mangleFoo = function() { this.foo = 100; };
x.definePrivateProperties('foo');
delete foo.prototype.mangleFoo;
x.mangleFoo();

(Кстати, посмотрим, что мы там делали? Мы можем добавить функцию и дать ей доступ на "частный" свойства почти по желанию.) Для того, чтобы предотвратить это...я не знаю. пересмотреть definePrivateProperties после его запуска один раз?

В отличие от стандартного метода (скрытие переменной в шов) не склонна к такого шаманства.

6
ответ дан 31 октября 2011 в 11:10 Источник Поделиться

Похоже, что вы можете избавиться от ивала

this[ fn ] = eval( '(' + proto[fn] + ')' );

с его заменой

this[fn] = (proto[fn]);

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

2
ответ дан 24 августа 2011 в 04:08 Источник Поделиться

this[ fn ] = eval( '(' + proto[fn] + ')' );

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

this[ fn ] = (function (f) { return f.apply(this, arguments); })(proto[fn]);

Вы также используете нестандартные конструкции, такие как свойство__proto__. Может быть, было бы лучше использовать getPrototypeOf

0
ответ дан 24 октября 2011 в 10:10 Источник Поделиться