JavaScript中的`of`关键字(用于for...of循环)

12
我刚刚在 MDN 上看到了 Firefox SDK JavaScript 中使用的一个关键字,这是我从未见过的: (链接)
var tabs = require('sdk/tabs');
for (let tab of tabs)
  console.log(tab.title);

“of”关键字是由Mozilla发明的还是被标准化了?

1
ES6的一部分。在Google上搜索“for of loop ES6”应该能找到相关内容。 - user663031
5
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of - artm
2个回答

18

for...of循环可以遍历属性,它是在ECMAScript 2015中添加到JavaScript规范中的一个特性

考虑到这个问题的背景是Firefox插件,问题不在于其他浏览器是否可用或何时可用。问题在于ECMAScript 2015特性何时添加到Firefox中,以及使用它可能导致的向后兼容性限制。

它在Firefox 13中添加到Firefox。因此,使用它将导致限制您的附加组件为Firefox 13+。鉴于截至2014年10月的当前版本是Firefox 33.0,并且在Firefox 13和现在之间已经发布了多个ESR版本,使用for...of循环可能不会显着减少能够使用您的附加组件的人数。您使用的其他某些功能可能会限制您的附加组件仅适用于更近期的版本。

使用for...of

Array.prototype.forEach()不同,for...of循环不仅限于数组,还将迭代其他类型的iterable objects,其中包括许多不同类型的对象。

有时会让人困惑的一件事是,for...of循环遍历的是属性的值,而不是属性键。根据你所做的操作,这可能非常方便,或者使得for...of循环不合适。

例如:for..of循环遍历NodeList

const listItems = document.querySelectorAll('li');

for (let item of listItems) {
    console.log('item text:', item.textContent); // "first", "second", "third", "fourth"
}
<ol>
    <li>first</li>
    <li>second</li>
    <li>third</li>
    <li>fourth</li>
</ol>

普通对象通常不是可迭代的(不能使用for...of

在普通对象上尝试使用for...of会抛出错误。

const obj = { first: 3, second: 5, third: 7, fourth: "hello" };

// with Object.keys()

for (let value of obj) { //This is an error. obj is not iterable
    console.log('value:', value);
}

迭代对象属性值的其他方法

Array.prototype.forEach()

如果您正在寻找执行类似任务的其他方法,MDN显示示例使用Array.prototype.forEach()迭代ArraysObjects的属性值:

forEach直接在从Object.values()获得的对象值上进行:

const obj = { first: 3, second: 5, third: 7, fourth: "hello" };

// with Object.keys()

Object.values(obj).forEach(function (value) {
    console.log('value:', value); // logs "3", "5", "7", "hello"
});

forEach 遍历从 Object.keys() 获取的对象键:

const obj = { first: 3, second: 5, third: 7, fourth: "hello" };

// with Object.keys()

Object.keys(obj).forEach(function (key) {
    //obj[key] is the property value
    console.log('key:', key);        // logs "first", "second", "third", "fourth"
    console.log('value:', obj[key]); // logs "3", "5", "7", "hello"
});

forEach over an Array's values:

const arr = [ 3, 5, 7 ];

arr.forEach(function (value, index) {
    console.log('value:', value);     // logs "3", "5", "7"
    console.log('index:', index);     // logs "0", "1", "2"
});

for..in

使用 for..in 循环的主要缺点是它会迭代对象的 可枚举属性,包括对象原型上的属性。这可能会导致意外错误。因此,除非你 知道 想要迭代的是不属于对象自身属性的可枚举属性(很少需要),否则总是测试循环的键值是否是对象自己的属性之一,可以使用 Object.prototype.hasOwnProperty() 或其他方法。
虽然这不是必需的,但最好使用一个已知为好的 Object.prototype.hasOwnProperty() 的副本,因为任何对象都可以定义自己的 hasOwnProperty,无论是有意还是出于错误。

const obj = { first: 3, second: 5, third: 7, fourth: "hello" };

// with for..in

for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
        //obj[key] is the property value
        console.log('key:', key); // logs "first", "second", "third", "fourth"
        console.log('value:', obj[key]); // logs "3", "5", "7", "hello"
    }
}

浏览器兼容性:

如果您想将您的插件移植到其他浏览器,或在网页中使用for...of,那么您应该了解此功能是何时添加到各种浏览器中的。可以在MDN上的浏览器兼容性表格中看到,主要问题是它不受Internet Explorer支持。

这是截至2018年3月11日的MDN的兼容性表格

browser compatibility

  1. Chrome 29-37:使用for...of循环功能需要在偏好设置中启用。在chrome://flags中,激活“启用实验性JavaScript”条目。
  2. 在Firefox 51之前,使用const关键字的for...of循环结构会抛出SyntaxError(“常量声明中缺少=”)。

非常有用的答案,我不知道它在FF13中出现。 - Noitidart

1
这是一个EcmaScript 6的特性,不稳定且并非所有现代浏览器都支持。您需要等待其稳定或使用类似Traceur的转译器将ES6代码转换为ES5。

“不稳定” 是什么意思?另外,“transcoder” 是另外一种东西,也许你在寻找“transpiler” 这个词。 - user663031
他可以在不支持 ES6 的情况下使用 var tab in tabs 吗? - Noitidart
使用var tab in tabs这种“for...in”结构在所有浏览器中都得到了支持,你可以放心使用。说“不稳定”是指该特性在某些浏览器或某些版本的某些浏览器中添加了支持,但目前信任它的支持可能并不是明智的选择。 - ozantunca

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