Лучший способ получить доступ к закрытым членам в Javascript - PullRequest
7 голосов
/ 25 июня 2009

Прочитав немного о прототипной модели наследования в Javascript , я изменил свой стиль конструирования класса с

var Some_Class = function() {
    this.public_method = function() {
    };
    (function() {
        // constructor
    }).call(this)
}

до

var Some_Class = function() {
    (function() {
        // constructor
    }).call(this)
}
Some_Class.prototype.public_method = function() {
};

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

var Some_Class = function() {
    var private_member = 'whatever';

    (function() {
        // constructor
    }).call(this)
}
Some_Class.prototype.public_method = function() {
    return private_member; // not possible
};

Прочитав статью здесь (конструктор, созданный замыканием), я вышел с этим

var Some_Class = function() {
    var private_member = 'whatever',

    private_method = function(_some_value) {
        // private method implementation
    };

    if(!arguments.callee.prototype.public_method) {
        arguments.callee.prototype.public_method = function() {
            private_method.call(this, private_method);
        };
    }

    (function() {
        // constructor
    }).call(this)
}

Однако, каковы недостатки этого? или есть лучший способ сделать это, если я хочу получить доступ к приватный член в публичном методе?

Ответы [ 5 ]

11 голосов
/ 25 июня 2009

Мой ответ не отвечает: в JavaScript нет встроенного доступа private, но это нормально, потому что YAGNI . Вот как я делаю private членов в моем коде:

function Some_Class() {
    this._private_member = 'whatever';
}

Some_Class.prototype._private_method = function() {
};

Это достаточно хорошо. Не стоит прыгать через обручи, когда единственная реальная цель private - защитить себя от ... себя.

(Я говорю это, потратив много часов на то, чтобы поиграть с каждой перестановкой замыканий и прототипов, как и вы, и, наконец, сказать: «Винт, это не стоит»)

10 голосов
/ 25 июня 2009

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

В вашем примере private_method (и его окружение) совместно используются всеми объектами - поскольку ваше закрытое public_method создается только при первом создании объекта (и привязывается к свойству prototype конструктора, которое устанавливает внутреннюю цепочку прототипов созданного объекта) ) - так что используется private_method только тот, который был создан в первый раз.

Вот пример кода, который поможет проиллюстрировать происходящее:

  var global = 1;

  var Some_Class = function() {
    var private_method = 'whatever';
    var now = ++global;
    print("outer now: " + now );
    private_method = function(_some_value) {
        // private method implementation
        print("inner now: " + now);
    };

    if(!arguments.callee.prototype.public_method) {
        arguments.callee.prototype.public_method = function() {

            private_method.call(this, private_method);
        };
    }

    (function() {
        // constructor
    }).call(this)
}

new Some_Class().public_method(); // outer now: 2, inner now: 2
new Some_Class().public_method(); // outer now: 3, inner now: 2
new Some_Class().public_method(); // outer now: 4, inner now: 2

Вы уверены, что это то, что вы хотите?

Если ваш private_method не должен ссылаться на состояние окружающего объекта, то я вижу небольшую выгоду в том, чтобы делать то, что вы делаете.

Что я обычно делаю (если мне нужно использовать «new» для создания моего объекта):

function MyClass() {
  var private_var = 1; 
  function private_func()
  {

  }
  this.public_func = function() 
  {
     // do something
     private_func();
  }
  this.public_var = 10;
}

var myObj = new MyClass();

Недостатком этого подхода является то, что каждый раз, когда вы создаете объект с помощью 'new', вы заново создаете все замыкания. Но если мой профилировщик не скажет мне, что этот выбор дизайна должен быть оптимизирован, я предпочитаю его простоту и ясность.

Также я не вижу в вашем коде пользы от следующих действий:

  (function() { }).call(this);  // call the constructor

Почему вы создаете отдельную область в конструкторе?

1 голос
/ 07 августа 2012

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

function SomeClass() {

   var _private = 0;
   this.public_acessor = function() {return _private};
}

Любой пользователь может написать:

SomeClass._not_private_anymore = 1;
SomeClass.public_acessor = function () {return this._not_private_anymore}; 

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

1 голос
/ 25 июня 2009

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

0 голосов
/ 26 июня 2011

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

...