如何检测代理对象中获取序列的结尾?

How to detect the end of a get sequence in a proxy object?

为了避免访问深度嵌套的属性时出错,我写了一个proxy-returning函数:

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 无法判断它何时到达路径的尽头。这意味着它不能 return undefined 表示 属性 确实不存在。这也意味着您不能有默认值:

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

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

我的代理对象如何检测 属性 查找的结束?

This answer 或多或少适用于此,原因相同。

您无法检测到访问链的结尾,因为它与前面的访问没有任何不同。在运行时,以下代码实际上等同于 let r = a.x.y.z.

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

如果你真的想在你正在编写的代码中使用这种安全导航,你最好的选择可能是使用这两个 Babel 插件([1], [2]) to let you use the proposed optional chaining and nullish-coalescing 运算符(?.??,它们正在成为 JavaScript 的一部分。它们提供了一种更简洁、更少混淆的方式来做这类事情。

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

但是,如果您真的想自己实施 "safe" 访问,可以使用 一些技巧来解决这个问题。

一个可能需要最少额外工作的技巧是保留一个名称来指示安全访问链的末端。 (我过去在 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

this blog post中详细介绍了另一个技巧。