Как имитировать модификаторы доступа в JavaScript с помощью библиотеки Prototype? - PullRequest
2 голосов
/ 24 декабря 2009

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

SampleBase = Class.create({
    /* virtual public constructor */
    initialize: function(arg1, arg2)
    {
        // private variables
        var privateVar1, privateVar2;

        // private methods
        var privateMethod1 = function() { }
        function privateMethod2() { }

        // public (non virtual) methods
        this.publicNonVirtual1 = function() { return privateVar1; }
        this.publicNonVirtual2 = function() { return privateVar2; }
    },
    // public methods (that cannot access privates)
    publicVirtual1: function() { /* Cannot access privates here. */ },
    publicVirtual2: function() { /* Cannot access privates here. */ }
});

Это менее чем идеально по нескольким причинам:

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

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

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

Message = Class.create({
    initialize: function(message)
    {
        var _message = message;
        this.getMessage = function() { return _message; }
        this.setMessage = function(value) { _message = value; }
    },
    printMessage: function() { console.log(this.getMessage()); },
    appendToMessage: function(value) { this.setMessage(this.getMessage() + value); }
});

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

Message = Class.create({
    initialize: function(message)
    {
        var _message = message;
        this._printMessage = function() { console.log(_message); }
        this._appendToMessage = function(value) { _message += value; }
    },
    printMessage: function() {this._printMessage(); },
    appendToMessage: function(value) { this._appendToMessage(value); }
});

Эта новая версия ограничивает публичный доступ для этого класса, но несколько избыточна. Не говоря уже о том, что appendToMessage переопределено в подклассе, третья сторона все еще может вызвать _appendToMessage для доступа к исходному методу, который не годится.

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

EDIT: Я подозреваю, что отсутствие обратной связи (кроме комментариев bobince ) не означает, что я прав, потому что вы не можете взять это дальше, но я думаю, что немного уточнить дело. Я не думаю, что можно приблизиться к защите других языков. Мне больше интересно знать, где лежат пределы и насколько точно мое понимание вовлеченных принципов. Однако я думаю, что было бы интересно, если не полезно, если бы мы могли заставить различные уровни защиты функционировать до такой степени, чтобы непубличные члены не отображались в цикле for ... in (или в Prototypes Object.keys, которые использует for ..in), даже если это люди, которые знают, что они делают, могут все еще нарушать правила, делая такие вещи, как работа с моими прототипами. В конце концов, как bobince говорит, что «им некого обвинять, кроме самих себя»

Теперь прокомментируем проблему, поднятую bobince :

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

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

  • Только мои публичные члены уязвимы таким образом.
  • Если мои общедоступные виртуальные методы «скомпрометированы» таким образом, то «скомпрометированные» методы все равно не будут иметь доступа к закрытым членам.
  • Если мои публичные (не виртуальные) члены «скомпрометированы» таким образом, то, в отличие от исходной версии метода, «скомпрометированная» версия не будет иметь доступа к закрытым членам.
  • Насколько я знаю, единственный способ получить доступ к закрытым членам с помощью методов, определенных вне метода initialize, - это воспользоваться ошибкой в ​​том, как некоторые браузеры обрабатывают вызовы eval.

Ответы [ 2 ]

7 голосов
/ 24 декабря 2009

Как сделать защищенный элемент в JavaScript: в начале имени поставьте подчеркивание.

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

Так что не пытайтесь. Просто сделайте так, как это делают Python: помечайте метод как то, что посторонние не должны вызывать, и покончите с этим. Если кто-то использует ваш код и полагается на участника с _ в начале имени, это его проблема, и им некого винить, кроме себя, когда ломается их скрипт. Между тем вы упростите этапы разработки и отладки, не имея строгих частных и защищенных членов.

Затем вы можете выбрать для каждого экземпляра (для удобства привязки обратного вызова) или для прототипированных членов (для эффективности), независимо от того, хотите ли вы, чтобы они были частными, и вы не потрясете себя несоответствием. *

2 голосов
/ 03 февраля 2011

http://www.crockford.com/javascript/private.html

Объясняет все это ...

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