测试自己属性的晦涩方法

Obscure way to test for own properties

在书 Javascript:权威指南第六版 David Flanagan 的第 147 页中,作者讨论了使用 for..in 循环遍历数组时的警告,以下是引用(粗体)是我的)

...For this reason you should not use a for/in loop on an array unless you include an additional test to filter out unwanted properties. You might use either of these tests:

for(var i in a) {
   if (!a.hasOwnProperty(i)) continue; // Skip inherited properties
   // loop body here
}

for(var i in a) {
   // Skip i if it is not a non-negative integer
   if (String(Math.floor(Math.abs(Number(i)))) !== i) continue;
}

现在第一个代码片段对我来说很清楚了,继承的属性将被跳过。

但是,我根本不清楚第二个代码片段。

根据我的理解,第二个代码片段将跳过 数组的任何非数字 属性(无论是自己的 属性 还是不是(不像第一个代码片段))

但如果是这样的话,你不能只使用像这样的简化测试:

if (Number(i) != i) continue;

那么作者为什么要用这么复杂的表达方式呢?

我是不是漏掉了什么?

不,这里有一些会失败的例子:

浮点数:

var a = [1, 2, 3];
a['1.5'] = 'busted';
for(var i in a) {
    if (Number(i) != i) continue;
    document.getElementById('output1').textContent += i + '\n';
}
for(var i in a) {
    if (String(Math.floor(Math.abs(Number(i)))) !== i) continue;
    document.getElementById('output2').textContent += i + '\n';
}
<h3>Number(i) != i</h3>
<pre id="output1"></pre>
<h3>String(Math.floor(Math.abs(Number(i)))) !== i</h3>
<pre id="output2"></pre>

负数:

var a = [1, 2, 3];
a['-5'] = 'busted';
for(var i in a) {
    if (Number(i) != i) continue;
    document.getElementById('output1').textContent += i + '\n';
}
for(var i in a) {
    if (String(Math.floor(Math.abs(Number(i)))) !== i) continue;
    document.getElementById('output2').textContent += i + '\n';
}
<h3>Number(i) != i</h3>
<pre id="output1"></pre>
<h3>String(Math.floor(Math.abs(Number(i)))) !== i</h3>
<pre id="output2"></pre>

这就是 Math.absMath.floor 呼叫所要防范的。

顺便说一句,对数组索引使用 for in 循环确实没有任何优势。我建议使用基于索引的循环。