为什么 JavaScript 属性访问器允许使用包含单个属性名称的任意嵌套数组?

2023-12-10

刚刚回答完question,并且对为什么以下内容似乎在 JavaScript 中工作感到有点困惑:

const source = {
  last: "Capulet"
};

const srcKeys = Object.keys(source);

console.log(source[srcKeys]);
console.log(source[[[[srcKeys]]]]);
console.log(source[[],[[[srcKeys]]]]);
console.log(source[[],[[srcKeys]]]);
console.log(source[[[]],[],srcKeys]);
console.log(source[[[]],[[srcKeys]]]);

在尝试了解兔子洞有多深时,我发现以下方法不起作用:

const source = {
  last: "Capulet"
};

const srcKeys = Object.keys(source);

console.log(source[[[],[[srcKeys]]]]);
console.log(source[[[],[],[[srcKeys]]]]);
console.log(source[[[[]],[[srcKeys]]]]);

这里的逻辑是什么?


做了一些之后research on这个问题,事实证明,其实有一种解决疯狂的方法。

逗号运算符

从我的测试来看,这一点并不是很明显,但理解有效的示例非常有用。

console.log(source[srcKeys]);
console.log(source[[[[srcKeys]]]]);
console.log(source[[],[[[srcKeys]]]]);
console.log(source[[],[[srcKeys]]]);
console.log(source[[[]],[],srcKeys]);
console.log(source[[[]],[[srcKeys]]]);

您会注意到,这些陈述实际上存在一种最初并不明显的模式。

每个属性访问器要么是一个逗号表达式(它将计算出表达式中的最后一个值 - 通常是一个数组),要么只是一个数组。

console.log(source[srcKeys]); // => array
console.log(source[[[[srcKeys]]]]); // => array
console.log(source[[],[[[srcKeys]]]]); // => comma expression
console.log(source[[],[[srcKeys]]]); // => comma expression
console.log(source[[[]],[],srcKeys]); // => comma expression
console.log(source[[[]],[[srcKeys]]]); // => comma expression

更重要的是,每个数组要么是单元素数组,要么是单元素数组的嵌套数组.

有了这些知识,现在是尝试了解 ECMAScript 规范如何制定评估的好时机property accessors.

属性存取器

我不会再讲那些血淋淋的细节,而是总结一下几乎 99% 的情况下发生的情况:

属性表达式首先转换为字符串(除非它是Symbol自 es6 起),然后返回对具有给定属性名称的值的引用


现在我们知道 JavaScript 将简单地尝试将任何属性访问器转换为字符串,并使用该字符串作为属性名称。

除此之外,数组在转换为字符串时还有一个有趣的行为。您可以阅读此其他内容answer深入了解数组如何转换为属性名称。

不那么秘密的揭露

现在让我们将我们所知道的一切应用到给出的示例中,看看为什么有些有效而有些无效。

首先,让我们看一下不起作用的示例:

console.log(source[[[],[[srcKeys]]]]); // => property accessor expression is [[],[[srcKeys]]]
console.log(source[[[],[],[[srcKeys]]]]); // => property accessor expression is [[],[],[[srcKeys]]]
console.log(source[[[[]],[[srcKeys]]]]); // => property accessor expression is [[[]],[[srcKeys]]]

每个表达式的一个一致的细节是它们都是数组multiple元素。很快就会明白为什么这些没有给我们带来预期的价值,但之前的却给了我们预期的价值。为此,我现在将展示结果toString在所有阵列上。

const source = {
  last: "Capulet"
};

const srcKeys = Object.keys(source);

// console.log(source[srcKeys]);
console.log(srcKeys.toString());

// console.log(source[[[[srcKeys]]]]);
console.log([
  [
    [srcKeys]
  ]
].toString());

// console.log(source[[],[[[srcKeys]]]]);
console.log(([], [
  [
    [srcKeys]
  ]
]).toString());

// console.log(source[[],[[srcKeys]]]);
console.log(([], [
  [srcKeys]
]).toString());

// console.log(source[[[]],[],srcKeys]);
console.log(([
  []
], [], srcKeys).toString());

// console.log(source[[[]],[[srcKeys]]]);
console.log(([
  []
], [
  [srcKeys]
]).toString());

// console.log(source[[[],[[srcKeys]]]]);
console.log([
  [],
  [
    [srcKeys]
  ]
].toString());

// console.log(source[[[],[],[[srcKeys]]]]);
console.log([
  [],
  [],
  [
    [srcKeys]
  ]
].toString());

// console.log(source[[[[]],[[srcKeys]]]]);
console.log([
  [
    []
  ],
  [
    [srcKeys]
  ]
].toString());

我们终于得到它了。第一个有效的示例的 toString 值为last,而其余​​的则没有。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 JavaScript 属性访问器允许使用包含单个属性名称的任意嵌套数组? 的相关文章

随机推荐