Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Ограничения getter (setter) (https://javascript.ru/forum/misc/80683-ogranicheniya-getter-setter.html)

Launder 13.07.2020 15:10

Ограничения getter (setter)
 
Решил запаролить доступ к объекту (как пример "оболочки" на объект), без использования прокси.
Попробовал такой нехитрый способ:
let obj =
     {
         a: 145,
         b: 146,
         c: 147
     }

let pass = 'lex';

let passObj =
               {
                  get p()
                         {
                            return prompt('password?') == pass ? obj : alert('access denied');
                         }
               }
     

obj = passObj.p; //перезаписываем ссылку на объект

alert( obj.a );
alert( obj.b );
alert( obj.c );


Радостно обнаружил, что пароль работает только один раз при присвоении, затем видимо, результат записывается в passObj.p, а затем обратно в obj. Немного согрелись:)
При этом если мы в геттере для passObj.p будем возвращать примитив, например число, то к нему будет нормальный доступ по паролю.
Читаю MDN:
1. нуль параметров (понятно)
2. Геттер не должен появляться в объектном литерале вместе с другим get (ок) или через ввод данных для того же свойства (а почему же тогда запрос пароля, для примитива работает?)
3. Он может иметь идентификатор, который является либо числом, либо строкой; - вот тут непонятно, имеется в виду, что результатом работы геттера может быть либо число, либо строка?...
В спецификации (искал "getter") я немного запутался, соотнести указанные там шаги с какими-то реальными операциями у меня не получилось...
Например, как расшифровать запись:
Код:

2. Let desc be ? O.[[GetOwnProperty]](P).
и где может быть общая информация, как выше в MDN, к сожалению, не совсем понятно...
В общем, хотелось бы понять, может ли геттер возвращать объект.
Понять получше, что он вообще может...
Ну и как бонус, попробовать найти альтернативу прокси в замыкании...:write:

Nexus 13.07.2020 17:43

Вы что-то очень странное написали, чтобы понять что у вас в коде происходит нужно пару минут (мне, во всяком случае).
Зачем вам подобная конструкция - непонятно.

"Запаролили" свойства объекта и сразу же к ним обращаетесь.
Вопрос: нафига нам вообще объект passObj, если проверка пароля происходит сразу же после? Чем обычный if не угодил?

Паролить объекты на клиенте - глупость, посмотреть их содержимое труда не составит.

Если хотите поиграться, то используйте для своей задачи Proxy.

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

Строка 19 - вызов геттера из строк 12..15;
Если пароль верный, то в переменную obj записывается объект, на который до перезаписи значения ссылается переменная obj. Если пароль кривой, то в переменную obj записывается undefined, т.к. alert ничего не возвращает.

В итоге вы либо каждый раз (строки 21..23) просто обращаетесь напрямую к изначальному объекту, либо к undefined.

Launder 13.07.2020 19:18

Ошибка ясна, геттер выдаёт значение, а значение - объект. Вызвав один раз, мы сохранили прямую ссылку на объект в переменную, вот пароль и не нужен. Грубо говоря, при вызове
alert( passObj.p.a );
а далее, в конце вместо a поставлять b и c, то пароль потребуется каждый раз. Также можно сделать функцию
let getObj = function acc() {  return passObj.p  }
и вызывать вот так:
alert( getObj().a );

Но, поместить геттер в переменную, похоже, увы, не получится - только её результат. А результат уже обнаружит себя, то есть поместить функцию (которая запрашивает пароль), под видом "просто объекта", уже врят ли получится...
Паролить на клиенте я не собираюсь, просто это наглядный(для меня) пример оболочки на объект. Как раз и хочу понять, насколько прозрачную можно сделать оболочку на объект и есть ли, при этом, альтернатива и прокси.

Nexus 13.07.2020 20:02

function protectObject(object, password) {
    if (!password) {
        return object;
    }

    return new Proxy(object, {
        get(target, name) {
            const pwd = prompt('Enter password');
            if (!pwd || pwd !== password) {
                throw new Error('Access denied');
            }

            return target[name];
        }
    });
};

var a = {a: 1, b: 2, c: 3},
    p = protectObject(a, 'asd');

try {
    alert(p.a);
} catch (e) {
    alert(e.message);
}

Launder 13.07.2020 20:30

Я пробовал подобное.


Часовой пояс GMT +3, время: 04:02.