如何使用解构数组获取长度属性

14
我在一篇文章中看到了这个解构表达式。
const words = ['oops', 'gasp', 'shout', 'sun'];
let { length } = words;
console.log(length); // 4

我该如何得到 length 的值为 4?我知道 .length 是数组的一个属性,但这个语法是怎么工作的呢?它似乎执行了 let length = words.length;,实际上在 Babel 中也是这样输出的。但我的问题是背后的逻辑是什么?让我困惑的是,它混合了一组值和使用 {length}
我已经阅读了 MDN 的说明,但无法看到这个例子的解释。

6
你正在解构一个对象{}… 数组也是一种对象… 因此…ES2015+值得庆祝。 - Jaromanda X
1
{ length } = someobject is telling the processor to create a variable named length with a value that is stored in the property named length of the object on the right hand side. Same works if you do { kat } = { kat:3 } - Patrick Evans
实际上,Babel的输出应该足以了解正在发生的事情 - 这并没有什么神秘的(当然除了新语法)。 - Jaromanda X
3个回答

15

介绍

我曾经有同样的问题,所以我阅读了文档,最终我明白了变量(length)只是被赋予了对象中与变量同名的键所对应的值(words[length]).

这可能不太容易理解,因此我将分两步来解释这种解构方式,然后展示它如何应用于这种情况。

接下来,我将提供一个最后(很酷的)例子,这个例子最初使我感到困惑,促使我研究这个主题。它也是一个重复问题中描述的确切问题。


解构

这种语法称为对象解构赋值(MDN):

let a, b;

({a, b} = {a: 1, b: 2});
a; // 1
b; // 2


({b, a} = {c: 3, b: 2, d: 4, a: 1});
a; // 1
b; // 2

同样的结果 - 顺序无关紧要!

左边的变量(ab)被赋值为对象(右边)中对应键的值。


const obj = {a: 1, b: 2};
let {a, b} = obj;

a; // 1
b; // 2

我们可以将右侧的对象存储到一个变量中(在此例中为obj),然后使用相同的语法(不需要括号)。


应用于您的示例(数组)

最后,让我们将words数组显示为对象(数组实际上是对象的一种形式)。

如果您在Chrome控制台中输入['oops', 'gasp', 'shout', 'sun'],您将看到以下内容:

chrome控制台输出

const words = {0: 'oops', 1: 'gasp', 2: 'shout', 3: 'sun', length: 4};
let { length } = words;
console.log(length); // 4

与上面类似,它将把words对象/数组(右侧)中相应键的值设置为length变量(左侧)。words[length]的值为4,因此length变量(左侧)现在也具有4的值。


解构赋值实用示例

来自Wes Bos的博客

给定一个person对象,如何创建引用其属性的全局变量?

const person = {
  first: 'Wes',
  last: 'Bos',
  country: 'Canada',
  city: 'Hamilton',
  twitter: '@wesbos'
};

老派的风格:

const first = person.first;
const last = person.last;

解构的威力!

const { first, last } = person;

奖励内容: 结合 箭头函数 的酷用法 (MDN)

挑战: 返回一个新数组,其中包含输入数组中各个元素的长度。

这个例子展示了如何使用箭头函数。所有三种方法都可以解决这个问题,只是演示了一步步演进到最终变成简单的一行代码。

var materials = [
  'Hydrogen',
  'Helium',
  'Lithium',
  'Beryllium'
];

materials.map(function(material) { 
  return material.length; 
}); // [8, 6, 7, 9]

materials.map((material) => {
  return material.length;
}); // [8, 6, 7, 9]

materials.map(({length}) => length); // [8, 6, 7, 9]

在传递给map的输入数组的每次迭代中,我们将{length}参数设置为传入作为参数的materials的当前元素:

{length} = 'Hydrogen';

这段代码将length变量设置为当前字符串元素的length属性(稍后会详细讲解),然后简单地返回length的值给map函数,该函数最终返回一个新数组,其中所有元素都是原始数组长度。

补充说明:String(原始类型)与Array(对象)

“字符串”是“原始类型”,不是对象,因此它们没有属性,但是当您尝试调用诸如.length之类的属性时,该原始类型会被强制转换为String对象

这是Chrome控制台中的String对象的样子。请注意,它几乎与Array对象相同。 String(函数)是一个构造函数,因此调用new将创建一个新对象,该对象由该函数构造,并且其原型为String(对象)(这就是__proto__所指的内容):

Chrome控制台中的新字符串


2
不确定为什么有人投了反对票!很好的解释,清晰易懂。我们现在明白了 :) - leonormes
比被选为解决方案的答案更加超级好! - TheBestPessimist
非常有用的答案。感谢您抽出时间进行解释。 - user2879303
谢谢。讲解得非常好。 - NinjaTS

12

将代码视为

const words = {0:'oops', 1:'gasp', 2:'shout', 3:'sun', length:4};
let { length } = words;
console.log(length);

基本上就是这样(不用管数组附带的其他内容)

现在有意义了吗?


1
那么我的 words 数组被强制转换为具有 length 属性的对象了吗? - leonormes
2
不完全正确,JavaScript 中除了原始类型以外的所有东西都继承自 Object - 查看数组的原型链即可。 - Jaromanda X
2
强制转换的例子可以是,例如 words + ''...将输出强制转换为字符串"oops,gasp,shout,sun" - Jaromanda X
是的,这有道理,但为什么他们要制作这样的复杂结构,这种结构的演变目的会是什么,有任何个人建议或经验吗? - badarshahzad

2

如果你在{}之间添加一个属于Array的属性,它的值将被复制。
这里我们检查属性constructor。将构造函数记录到控制台。

如果你添加一个不属于数组的属性,将返回undefined

另一个例子

const words = ['oops', 'gasp', 'shout', 'sun'];
let { constructor } = words;
console.log(constructor); 

We are testing for something will return undefined

const words = ['oops', 'gasp', 'shout', 'sun'];
let { something } = words;
console.log(something);


那么它正在检查属性length的原型链。所以如果我将其更改为nonsense,它会返回undefined - leonormes
现在检查答案。 - Sagar V
将构造函数记录到控制台。 - 好吧,在 Firefox 中实际上记录了 function Array() {[native code]} :p - Jaromanda X
抱歉,我以为您的意思是字面上输出“constructor function” - 我的错误。 - Jaromanda X
由于它是本地代码,函数主体只会显示为这样。您可以通过键入 alert; 来检查它,将会记录 function alert() { [native code] } - Sagar V
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接