Node.js v8 HOLEY 数组意外行为

Node.js v8 HOLEY arrays unexpected behavior

看完 Mathias Bynens 关于 HOLEY 和 PACKED 数组的报告后,我做了一些实验并得到了意想不到的行为。看两种情况:

// CASE #1
const array = [0,1,2,3,4,5,undefined]
array.__proto__[6] = 'some value'

console.log(array[6]) // "some value" expected but got undefined

// CASE #2
const array = [0,1,2,3,4,5]
array[10] = 'faraway value'
array.__proto__[6] = 'some value'

console.log(array[6]) // "some value" expected and received

那么,这些案例之间有什么区别?为什么在第一种情况下 return undefined 没有查看原型链?

在案例 #1 中,您明确地将 undefined 放入数组中。没有必要沿着原型链往上走,因为元素已经存在。比较:

var case1 = [0, 1, 2, 3, 4, 5, undefined, 7];
var case2 = [0, 1, 2, 3, 4, 5, , 7];
case1.hasOwnProperty(6);  // true
case2.hasOwnProperty(6);  // false
console.log(case1[6]);  // "undefined", loaded from object
console.log(case2[6]);  // "undefined", because no element was found (not on the object, and not on the prototype chain)
case2.__proto__[6] = "proto value";
console.log(case2[6]);  // "proto_value", loaded from prototype chain

你的情况 1

const array = [0,1,2,3,4,5,undefined] //array length is 7
array.__proto__[6] = 'some value' //will not work becasue 6th position already exists and JS will not load it from proto chain

console.log(array[6]) // you will get undefined because you assigned undefined at 6th position

你的情况 2

const array = [0,1,2,3,4,5] //length 6
array[10] = 'faraway value' //you added value on position 10, hence values between 6 and 10 is empty
array.__proto__[6] = 'some value' // you pushed value on position 6 using proto

console.log(array[6]) // you will get some value because position 6 is empty and hence JS tried to look into proto chain

所以基本上你可以说的是,__proto__赋值只有在分配的位置为空时才会起作用,因此如果位置为空,那么 JS 将在原型链中查找。

所以, 如果 array[6] 存在,则 array.__proto__[6] = 'value' 将不起作用或更改现有 array[6] 值的值,但如果 array[6] 为空,则执行 array.__proto__[6] = 'value' 并获取它将会起作用

旁注,使用 __proto__deprecated

未定义的 key 和未定义的 value.

是有区别的

当您编写 const array = [ 0, undefined ] 时,您正在创建一个双元素数组,其中第二个索引 (1) 的 value 未定义。

如果你写 const array = [ 0, , ] 你仍然在创建一个双元素数组,但它现在是 sparse 并且第二个索引(或 "key")没有' 甚至存在,即使它小于数组的 .length 属性.

由于没有密钥,解释器将改为签入原型。