mut*_*nka 2 javascript arrays prototype object ecmascript-6
通过将对象的原型方法设置为Array方法,该对象的行为类似于对象和数组之间的混合.下面是一个简单的例子:
function Foo() {}
Foo.prototype.push = Array.prototype.push;
Foo.prototype.forEach = Array.prototype.forEach;
var foo = new Foo();
foo.push('abc');
foo.length; // = 1 as expected. But wait, why isn't foo.length undefined? How/when did this property get attached to foo?
foo[1] = 'def';
foo.length; // still = 1. But foo={0:'abc',1:'def'}, Why not =2?
foo.forEach(function(item) {
console.log(item)
}); //shows only'abc' and not 'def'
foo.push('ghi');
foo.length; // = 2, and now foo = {0:'abc', 1:'ghi'}. So it overwrote the key=1, which means its accessing the same location, but the first approach did not change the length ( didn't become a part of the array ) why ?
foo.forEach(function(item) {
console.log(item)
}); //now shows 'abc' and 'ghi'Run Code Online (Sandbox Code Playgroud)
为什么所有这些奇怪的行为都会发生,为什么模仿像这样的数组并不好?
length物业如何设定?当您调用Array#push或在本例中调用Foo#push方法时.根据ECMAScript 2015规范:
22.1.3.17 Array.prototype.push(...... items)
[...]
- [...]
[...]
d.设len为len + 1
- 让setStatus被设置(Ø,
"length",LEN,真).
因此,当您调用该函数时,它会自动将length属性(如果它不存在)设置len为每次推送时递增的值.
现在,当您在数组中直接设置索引时,不会更新length属性.这是因为JavaScript中的数组是异常对象,当您直接设置属性时,这些对象会在内部增加长度.根据规范再次:
9.4.2数组外来对象
[...]
无论何时创建或更改Array对象的自有属性,都会根据需要调整其他属性以保持此不变量.具体来说,每当添加名称为数组索引的
length属性时,如果需要,属性的值将更改为该数组索引的数值之一;
根据定义,异域对象是覆盖所有普通对象所具有的内部方法的任何对象.在这种情况下,数组奇异对象会覆盖内部[[DefineOwnProperty]]方法,以便在定义数组的属性(如设置索引)时,需要执行额外的步骤以确保length更新属性等属性.您的Foo构造函数不会创建奇异的对象,因此它不会[[DefineOwnProperty]]像数组那样覆盖内部方法 - 因此length在直接在索引处定义值时不会更新.
push推到以前的指数?由于Foos不是外来物体,因此length在直接添加元素时不会自动递增,因此当您尝试第二次按下它时foo[1] = 'def',length保留1.如果我们Array#push再看一遍:
22.1.3.17 Array.prototype.push(...... items)
[...]
[...]
- 令items为List,其元素按从左到右的顺序,传递给此函数调用的参数.
[...]
因此,因为你的数组长度仍然是1 foo[1] = 'def'未修改length属性,因此它将在索引1处设置新的待推元素,因为长度为1.
同样的原则适用于Array#forEach.forEach依赖于length迭代数组.由于您的长度未被修改foo[1] = 'def'并且保持为1,因此forEach仅从索引[0,1]进行迭代,使其仅记录第一个元素.推送更新长度并使其从[0,2]迭代并记录两个元素.
这是因为数组是异国情调的对象.它们与常规对象不相处,因为常规对象从根本上不能实现与外来对象相同的行为.根据定义,异类对象会覆盖内部方法的默认行为,以实现功能所需的某些行为.在这种情况下,数组必须特别处理设置索引和管理长度 - 使用内部方法完成[[DefineOwnProperty]].对于常规对象,它不会覆盖[[DefineOwnProperty]]这么多基本操作因此无法正常工作 - 所以你不应该这样做.
但是,您可以使用诸如对象之类的奇异对象Proxy来实现您自己的[[DefineOwnProperty]]类似数组的代码来模拟行为.另一种方式,正如loganfsmyth所提到的,您可以使用ES2015类来正确扩展和子类内置的外来对象构造函数,从而模仿数组行为.
| 归档时间: |
|
| 查看次数: |
407 次 |
| 最近记录: |