我很久以前一直愿意让原生数组和常规对象之间的界限完全模糊,不仅扩展了与ES5中的数组相同的功能,而且还捆绑了我自己定制的方法包。 / p>
一些聪明人想到了这些范式的变化。就像Angus Croll在文章javascript-object-keys-finally中提到的那样:
“此外,阵列与常规物体之间的界线模糊(辅助 通过定制的getter和setter)我们可能会看到泛型的增长 “阵列式”对象,享受两全其美 - 非数字 标识符和对Array.prototype定义的丰富API集的访问。 通过引入,EcmaScript 5显然已经抢占了这一趋势 泛型方法,由一种类型定义但可由任何类型使用。“
在此过程中,他将文章中的内容编码为: extending-objects-with-javascript-getters
function extendAsArray(obj) {
if (obj.length === undefined || obj.__lookupGetter__('length')) {
var index = 0;
for (var prop in obj) {
if(!obj.__lookupGetter__(prop)) {
(function(thisIndex, thisProp) {
obj.__defineGetter__(thisIndex, function() {return obj[thisProp]});
})(index, prop)
index++;
}
};
obj.__defineGetter__("length", function() {return index});
}
return obj;
}
var myObj = {
left:50,
top:20,
width:10,
height:10
}
extendAsArray(myObj);
[].map.call(myObj,function(s){return s+' px'}).join(', ');
//"50px ,20px ,10px, 10px"
这种方法对我来说非常有趣。然而,它似乎也遭遇了几个严重的问题!
如何使用几个新属性扩展原始myObj模型?
我们是否应该对每个属性更改运行extendAsArray
以更新有关length
属性的内容?
当一个属性发生变化时,不仅仅是length
属性是相关的;
数组索引也应该更新,因为类似数组的属性请求肯定是未定义的。所以当
console.log(myObj.length) -> 4
myObj.zAxis=0
然后
console.log(myObj[4]) // -> undefined!
console.log(myObj.length) // -> 4!
我已相应修改了安格斯的代码,因此它支持根据请求自动更新length
属性:
function extendAsArray(obj) {
var index = 0;
for(var prop in obj){
if(!obj.__lookupGetter__(prop)){
(function(thisIndex, thisProp){
Object.defineProperty(obj, thisIndex, {
get: function(){return obj[thisProp]}
, enumerable: true
, configurable: true
, writeable: true
});
})(index, prop)
index++;
}
}
if(!obj.__lookupGetter__('length')){
Object.defineProperty(obj, 'length', {
get: function(){
return extendAsArray(obj);
}
, configurable: true
, writeable: true
});
return obj;
}
else{
return index;
}
}
问题是:当更改,添加或删除属性时,我们如何更新对象的数组索引及其length
属性?
我应该使用Object.watch
吗?
还有一个尚未解决的问题:如何干扰我自己的未经修饰的实用程序库,并以一致的方式为对象创建它?
我对两种类型使用相同的代码库:z.Object({}).mapEvery
与z.Object([]).mapEvery
请避免提及JQuery和Underscore。我有一个全面的,自定义的两种类型的方法列表,我愿意使用可能与我未经修改的标准完成的标准,我不愿意重构它!
答案 0 :(得分:1)
我想这是你的问题:
在更改,添加或删除属性时,如何更新对象的数组索引及其length属性?
您创建了执行此操作的方法,因此您基本上可以模仿Object internal methods。我不认为你可以用吸气剂和制定者做到这一点,但我可能错了。
其余的更多是评论而不是答案。
我很久以前一直愿意让原生阵列和普通物体之间的界线完全模糊
这条线已经完全模糊了。数组是对象,唯一能区分它们的是它们的特殊长度属性。
EcmaScript 5显然通过引入通用方法
来抢占这一趋势
ES5没有引入通用方法,至少从第3版就开始使用。
由一种类型定义但可由任何
使用
完全没有,事实上ES5更具限制性。在第3版中,call
和apply
使用Object(*thisArg*)
将 thisArg 强制转换为对象,或者如果未传递任何内容,则替换全局对象。在ES5中没有通过 thisArg 未经修改。
使用数组作为对象的限制与约定有关,而不是语言本身。大多数开发人员都认为应该使用对象或数组之间存在明显的区别。在极少数情况下,您确实需要像对象一样使用数组,但毫无疑问它们存在。 jQuery是Object利用Array属性的例子,例如:选择器收集的元素作为数字属性添加,并且有一个length属性,即元素的数量。通过这种方式,通用数组方法可以应用于jQuery对象(顺便说一下,所有这些都在ed 3中)。
Object.watch
方法在JavaScrpit™中,它不是ES5的一部分,因此请谨慎使用。
创建自己的内置对象版本的一个主要问题是,您可能最终将每个内置方法包装在本地方法中(比如jQuery几乎包装每个DOM方法)并开始设置getter和setter在每个属性上,或最终用函数调用来替换属性访问(例如jQuery的val
,attr
和prop
方法。如果表现很重要,那就相当乏味,而且很慢。
哦对不起,我提到了jQuery ......: - (
设计一个库或框架以充分利用该语言所具有的功能似乎更为明智,而不是试图强迫它执行它做得不好的事情,或者不做本机操作
但尝试满分。 : - )
答案 1 :(得分:0)
有一个图书馆watch.js,它正在关注房产更新或新增加的房产。 try out!
它正在使用setInterval,因此它不是性能友好的。
当和谐消失时,我们可以做一些简单的事情:
Object.observe(obj,Observer);
检查规格: Harmony
但是,当后来的对象扩展不在焦点时,我可以在初始化时冻结整个对象,不会因为属性更改和属性添加而烦恼。
代码会相应更改:
extendAsArray = function z_extendAsArray(obj){
var index = 0;
for(var prop in obj){
if(!obj.__lookupGetter__(prop)){
(function(thisIndex, thisProp){
Object.defineProperty(obj, thisIndex, {
get: function(){return obj[thisProp]}
, enumerable: true
, configurable: true
, writeable: true
});
})(index, prop)
index++;
}
}
if(!obj.__lookupGetter__('length')){
Object.defineProperty(obj, 'length', {
value:index
});
if(!Object.freeze){
Object.defineProperty(Object, "freeze", {
enumerable: false
, configurable: false
, writable: false
, value: function (obj) {
var props = Object.getOwnPropertyNames(obj);
for(var i=0; i<props.length; i++){
var desc = Object.getOwnPropertyDescriptor(obj,props[i]);
if("value" in desc ){
desc.writable = false;
}
desc.configurable = false;
Object.defineProperty( obj, props[i], desc );
}
return Object.preventExtensions(obj);
}
});
}
Object.freeze(obj);
}
return obj;
};
此外,我还发现了上一篇文章中提到过的安格斯·克罗尔(Angus Croll)所谈到的内容。
“是的,我们可以利用井下编写的库提供的等效功能,例如underscore.js,但我们仍然被锁定在非标准的反向签名中,其中方法是静态的,对象只是额外的参数 - 对于仅实例语言的笨拙安排。在某些时候,所有支持的浏览器都将符合ES5标准,此时,填充的代码库可以简单地删除它的填充库并继续进行,而未经修改的代码库必须在主要重构或永久非选择之间进行选择。标准和静态实用程序库。“