扩展常规对象以支持ES5 Array功能的问题
Problems with extending regular Objects to support ES5 Array capabilities
我很久以前就愿意让原生数组和常规对象之间的界限完全模糊,不仅扩展具有与ES5中数组相同功能的对象,而且在两边捆绑我的自定义方法包。
一些聪明人想到了这些范式的变化。就像Angus Croll在文章javascript-object-keys-finally:
中提到的那样在此过程中,他在文章中编码了一些东西:extending-objects-with-javascript-getters"此外,随着数组和常规对象之间的界限变得模糊(辅助)通过自定义getter和setter),我们可能会看到泛型的增长"类数组"对象,它兼有两个世界的优点——非数字标识符和对Array.prototype定义的富API集的访问。EcmaScript 5通过引入泛型方法,由一种类型定义,但可被任何类型使用。"
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!
我已经修改了Angus的代码,所以它支持自动更新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
吗?
还有一个未解决的问题:如何干扰我自己的unshimmed实用程序库,使它也以一致的方式为对象?
我对这两种类型使用相同的代码库:z.Object({}).mapEvery
和z.Object([]).mapEvery
做同样的事情
请避免提及JQuery,以及下划线。对于这两种类型,我已经有了一个全面的、自定义的方法列表,我愿意使用可能与我的未修改的标准一起完成的标准,我不愿意重构它!
我猜这是你的问题:
我们如何更新对象的数组索引和它的长度属性,当一个属性被改变,增加或删除?
你创建方法来做这件事,所以你本质上模仿Object的内部方法。我不认为getter和setter可以这样做,但我可能错了。
其余部分与其说是回答,不如说是评论。
我早就希望原生数组和普通对象之间的界限完全模糊了
界限已经完全模糊了。数组是对象,唯一将它们分开的是它们特殊的长度属性。
EcmaScript 5通过引入泛型方法
明显抢占了这一趋势。
ES5没有引入泛型方法,至少从第3版开始它们就在语言中了。
由一种类型定义,但可被任何
使用
一点也不,事实上ES5有更多的限制。在第3版中,call
和apply
使用Object(*thisArg*)
将thisArg强制转换为对象,或者在没有传递任何内容的情况下替换全局对象。在ES5中不是这样的,它传递thisArg不加修改。
使用数组作为对象的限制与约定有关,而与语言本身无关。大多数开发人员都清楚地看到对象和数组应该在什么时候被使用。在少数情况下,您确实需要像使用对象一样使用数组,但毫无疑问它们是存在的。jQuery是对象利用数组属性的一个例子,例如,由选择器收集的元素被添加为数字属性,并且有一个长度属性表示元素的数量。通过这种方式,通用数组方法可以应用于jQuery对象(顺便说一下,所有这些都在第3版中)。
Object.watch
方法在javascript™中,它不是ES5的一部分,所以请谨慎使用。
创建自己版本的内置对象的一个主要问题是,你可能最终会将每个内置方法包装在一个本地方法中(就像jQuery包装了每个DOM方法一样),并开始在每个属性上设置getter和setter,或者以函数调用来取代属性访问(例如jQuery的val
, attr
和prop
方法)。
哦,对不起,我提到了jQuery…
设计一个库或框架来充分利用语言所拥有的特性,而不是试图强迫它去做它做不好的事情,或者它本身不能做的事情,似乎是更明智的。
但是你的尝试给满分。:-)
有一个库watch.js,它可以监视属性更新或新属性添加。尝试!
它与setInterval一起工作,所以它不是性能友好的。
当Harmony不在时,我们可以做一些简单的事情:
Object.observe(obj,Observer);
检查规格:和谐
但是,当稍后的对象扩展不在焦点中时,可以在初始化时冻结整个对象,既不需要更改属性也不需要添加属性。
代码相应更改:
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;
};
我也发现了安格斯·克罗尔,谁已经提到了前一篇文章谈论它。
"是的,我们可以利用像underscore.js这样编写良好的库提供的等效功能,但我们仍然被锁定在非标准的反向签名中,其中方法是静态的,对象只是额外的参数——对于仅实例语言来说,这是一种笨拙的安排。在某种程度上,所有受支持的浏览器都将兼容ES5,到那时,被屏蔽的代码库可以简单地删除它的屏蔽库并继续使用,而未被屏蔽的代码库必须在重大重构或永远非标准的静态实用程序库之间做出选择。"
- 添加文字和评论功能更新Div
- JavaScript打印功能使日历停止工作
- 如何为json对象中的段发送array[]
- 每当您在选择器内移动鼠标时,悬停功能就会重复
- 如何防止网页加载后自动启动功能
- 除修剪外的其他功能
- 悬停功能触发器
- 使用angularjs向浏览器发送servlet响应(下载功能)
- Array.length似乎不起作用;console.log则显示其他情况
- 删除CKEditor工具栏按钮,但不删除功能
- 异步facebook功能
- 如何迭代Array.prototype函数
- 如何将chrome扩展功能移植到移动设备(特别是jquery和trello)
- Javascript 新的 Array 和 join() 方法
- jQuery滚动功能只工作一次
- Array.lenght = undefined
- 新Array(20)的实际功能
- 从对列表中获取JSON值作为Array(用于自动完成功能)
- 扩展常规对象以支持ES5 Array功能的问题
- 如何在不使用原型的情况下获得Object/Array.prototype的功能