Как определить конец последовательности получения в прокси-объекте?

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

const safe_access = obj =>
  new Proxy(obj, {
    get: (o, k) =>
      o[k] == null
        ? safe_access({})
        : typeof o[k] === 'object'
          ? safe_access(o[k])
          : o[k] });

Вот пример:

const a = safe_access({});
a.x.y.z; // no TypeError ????

Однако в своей текущей форме safe_access не может сказать, когда он достиг конца пути. Это означает, что он не может вернуть undefined, чтобы показать, что свойство действительно не существует. Это также означает, что у вас не может быть значений по умолчанию:

const a = safe_access({});
a.x.y.z || 42; // not 42

const {x: {y: {z = 42}}} = a;
z; // not 42

Как мой прокси-объект может обнаружить конец поиска свойства?


person customcommander    schedule 23.11.2019    source источник
comment
Используя этот синтаксис, я не думаю, что есть какой-либо способ узнать. Интересный вопрос однако.   -  person jfriend00    schedule 23.11.2019


Ответы (1)


Этот ответ более или менее применим здесь по тем же причинам.

Вы не можете обнаружить конец цепочки доступа, потому что она ничем не отличается от предыдущих доступов. Во время выполнения следующий код фактически идентичен let r = a.x.y.z.

let r = a;
{
    r = r.x;
    r = r.y;
    r = r.z
}

Если вы действительно хотите использовать такую ​​безопасную навигацию в коде, который вы пишете, лучше всего использовать эти два плагина Babel ([1], [2]), чтобы вы могли использовать предложенный необязательный операторы объединения и объединения null (?. и ?? соответственно), которые находятся на пути к тому, чтобы стать частью JavaScript. Они обеспечивают гораздо более аккуратный, гораздо менее запутанный способ сделать такого рода вещи.

let r = a?.x?.y?.z ?? 42;

Однако, если вы действительно хотите реализовать "безопасный" доступ самостоятельно, есть несколько приемов, которые вы можете использовать, чтобы обойти это.

Одна хитрость, которая, вероятно, требует наименьшей дополнительной работы, заключается в том, чтобы зарезервировать одно имя для обозначения конца цепочки безопасного доступа. (Раньше я делал что-то подобное на Python.)

function safe_access(value) {
    let obj = (typeof(value) === 'object') ? value : {};

    return new Proxy(obj, {
        value: value,
        get: function(target, property) {
            if (property === "$")
                return this.value;
            else
                return safe_access(target[property]);
        }
    });
}

let a = {'x': {'y': 123}};
// a.x.y is a proxy object
a.x.y.$ === 123
a.x.y.z.$ === undefined

Другой трюк подробно описан в эта запись в блоге.

person jirassimok    schedule 23.11.2019
comment
Эта техника в последнем посте в блоге, на который вы ссылаетесь, на самом деле довольно крутая. - person jfriend00; 23.11.2019