我希望(主要是出于学术原因)能够使用Object.defineProperty()
在数组的length
上设置访问者,因此我可以通知大小更改。
我知道ES6对象观察和watch.js,但我想尝试在没有额外库的情况下在ES5中执行此操作,即使这仅适用于V8 / Chrome。
示例数组:
var demoArray = ['one', 'two']
Alas Chrome,开箱即用,使得长度无法配置:
Object.getOwnPropertyDescriptor(demoArray, 'length')
Object {value: 2, writable: true, enumerable: false, configurable: false}
它不起作用:
Object.defineProperty(demoArray, 'length', { set: function(){ console.log('length changed!')} })
'TypeError: Cannot redefine property: length'
如您所见, configurable
false
- 因此失败是可以理解的。但是according to MDN it should be possible。
如何让defineProperty
处理数组的length
属性?这有用吗?
答案 0 :(得分:1)
根据ECMAScript 15.4.5.1,数组有自己的[[DefineOwnProperty]]
内部方法,因此configurable: false
不一定是立即的交易破坏者。这种方法的早期步骤是:
3。如果P为
"length"
,那么a。如果缺少Desc的
我是返回在传递[[Value]]
字段,那么[[DefineOwnProperty]]
,Desc和Throw作为参数的A上调用默认"length"
内部方法(8.12.9)的结果。
因此,如果属性描述符中没有value
属性,则将属性设置操作委派给默认的[[DefineOwnProperty]]
方法。 ECMAScript 15.4.5.2要求length
属性具有configurable: false
,因此默认方法将失败。
如果你做设置value
,为了避免进入默认方法,你也不能定义一个setter。尝试这样做会导致Chrome(或任何符合section 8.10的浏览器)出错:
TypeError: Invalid property. A property cannot both have accessors and be writable or have a value
因此,在任何符合ES5的实现中,似乎无法在数组length
上定义setter。
请注意,MDN文章似乎在谈论浏览器错误地拒绝使用value
来设置defineProperty
,通常应该,但有时候不是一个错误。
答案 1 :(得分:1)
“向Array.length添加事件侦听器将对应用程序的整体性能产生巨大影响,您应该尽力避免使用它”@Juno;
“不要依赖于重新定义数组的长度属性来工作,或以特定方式工作”MDN;
由于我们无法触及长度,因此我们可以更改push方法,然后使用它来为数组添加新值。
var a = ['a','b'];
a.push = function(x){
console.log('added: ',x,', length changed: ',(this.length+1));
this[this.length]=x
}
a.push('c');
答案 2 :(得分:1)
由于对此有了更多了解,Kangax's excellent article dedicated to the topic of subclassing Array涵盖了各种技术。一种名为数组原型注入的技术用于在流行的库(如Ractive.js)中对Array进行子类化。它依赖于非规范但流行的 __ proto __ ,但确实允许“访问者”长度。
答案 3 :(得分:1)
rmprop.js让您代理一个数组,以便您可以使用.length
属性执行任何操作:
var rmprop = require('rmprop');
var arr = rmprop(['my','array']);
// instead, length will return sum of lengths of all elements
Object.defineProperty(arr, 'length', {
get: function() {
return this[unprop.real].join('').length;
},
};
arr.length; // 7
答案 4 :(得分:0)
正如文件中明确指出的那样:
仅显示Internet Explorer 9及更高版本以及Firefox 23及更高版本 完全正确地实现长度属性的重新定义 数组。目前,不要依赖于重新定义的长度属性 一个数组,可以工作,也可以以特定的方式工作。乃至 当你可以依赖它时,没有充分的理由这样做。
包括Chrome在内的所有浏览器都不支持此功能,您应该找到另一种方法,在不更改数组的length
属性的情况下,首先执行您想要执行的操作。
一旦使用configurable: false
定义属性,实际上无法更改其配置。
所以在这种情况下,它是不可能的。即使它是,它也会出现性能问题,因为Array.length
被所有库随处使用,经常被访问,并且随处可见。
向Array.length
添加事件监听器将对您的应用程序的整体性能产生巨大影响,您应该尽一切可能避免它。