2

我很久以前一直愿意将本机阵列和常规对象之间的界限完全模糊,不仅扩展了与ES5中阵列具有相同功能的对象,而且还捆绑了我双方的自定义包装方法。扩展常规对象以支持ES5阵列功能的问题

几个聪明的人想到了这些范式的变化。就像安格斯·克罗尔文章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" 

这种做法是非常有趣的对我。但是,它也似乎遭受了一些严重的问题!

  1. 如何使用一些新属性扩展原始myObj模型? 我们是否应该在每次更改物业时都运行extendAsArray以更新其涉及的length属性?

  2. 当一个属性发生变化时,它不仅仅是相关的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的,并强调为好。我已经为这两种类型获得了一个全面的自定义方法列表,并且我愿意使用完成的标准和我未修改的标准完成,但我不愿意重构它!

回答

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; 
}; 

而且我已经发现了什么安格斯·克罗尔,谁已经由以前的帖子中提到一直在谈论它。

“是的,我们可以利用像underscore.js这样编写良好的库提供的等效功能,但我们仍然被锁定在非标准的倒排签名中,其中方法是静态的,而对象只是额外的参数 - 在实际使用中,所有支持的浏览器都是符合ES5标准的,在这种情况下,Shimmed代码库可以简单地删除它的Shim库并继续进行,而未修改的代码必须在主要的重构或永久性的非标准和静态实用程序库“。

1

我想这是你的问题:

我们如何与它的长度属性更新对象的数组索引一起当属性更改,添加或删除?

您创建方法来做到这一点,所以你基本上模仿Object internal methods。我不认为你可以用吸气剂和吸附剂来做到这一点,但我可能是错的。

其余更多的是评论而不是答案。

我早就愿意获得本地阵列和定期对象之间的界线变得模糊完全

线路已完全模糊。数组是对象,唯一使它们分开的是它们的特殊长度属性。

的EcmaScript 5显然通过将通用的方法抢先这种趋势,

ES5没有介绍的通用方法,他们由于至少ED 3已经在语言。

通过任何

由一种类型但可用定义一点也不,实际上ES5是更限制性的。在编辑3中,callapplythisArg强制转换为使用Object(*thisArg*)的对象,或者在没有任何内容传递时替换全局对象。 ES5中没有这样通过thisArg未修改。

使用数组作为对象的限制与约定有关,而不是语言本身。大多数开发人员在应该使用对象或数组之间看到明显的分歧。很少有情况下,您确实需要像对象一样使用数组,但毫无疑问,它们存在。 jQuery是Object利用Array属性的例子,例如由选择器收集的元素将作为数字属性添加,并且有一个长度属性即元素数量。这样通用数组方法可以应用于jQuery对象(顺便说一下,全部在3中)。

Object.watch方法在JavaScrpit™中,它不是ES5的一部分,所以谨慎使用。

创建您自己的内置对象版本的一个主要问题是您可能最终将每个内置方法都包装在本地方法中(比如jQuery几乎包装了每种DOM方法)并开始设置getters和在每个属性上设置setter,或者结束函数调用来替换属性访问(例如,jQuery的valattrprop方法)。相当繁琐,如果性能很重要,速度会变慢。

噢,对不起,我提到jQuery的... :-(

它只是似乎是更明智的设计库或框架,以使该语言的特征物尽其用,而不是试图迫使它做不好的事情,或者不做本地事情。

但尝试的满分。 :-)

+0

对象和数组之间的区别不仅仅是数组的长度属性。 据我所知:-)有几个ES5枚举方法,如地图,过滤器被添加到最近的浏览器,但IE9也支持它。 这些方法完全无法从本地对象获得。 – 2013-03-13 02:47:55

+0

这是: https://github.com/zludany/enumerable.js – 2013-05-21 02:14:14

+0

Both [* map *](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4。 4.19)和[* filter *](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.20)在ES5中,它们都是“有意通用的”而不是“要求[他们]这个值是一个数组对象“,所以他们将在具有合适属性的任何本地对象上工作。它们不需要与主机对象一起工作(但是在许多浏览器中都可以使用DOM对象)。 – RobG 2013-05-21 02:33:17