2

Я уже давно желаю, чтобы линия между естественными массивами и обычными объектами была полностью размыта, не только расширяя объект с теми же возможностями, что и массивы, полученные в ES5, но собираются вместе с мой собственный пакет методов с обеих сторон.Проблемы с расширением регулярных объектов для поддержки возможностей массива ES5

Пара умных людей думала об этих изменениях парадигмы. Как Ангус Кролл упомянул в статье javascript-object-keys-finally:

«Кроме того, как линия между массивами и обычными объектами размывают (автоматизированный заказных добытчиков и сеттера) мы, вероятно, увидеть рост общего «array- как «объекты, которые пользуются лучшими из обоих миров - неточечные идентификаторы и доступ к набору богатых API, определенному Array.prototype. 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 property?

  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 prop erty, когда свойство изменено, добавлено или удалено?

Должен ли я использовать Object.watch?

И все еще остается нерешенный вопрос: как вмешиваться в мою собственную библиотеку утилиты unshimmed, сделав ее также для объектов согласованным образом?

Я использую ту же кодовую для обоих типов: 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, после чего перевязанная кодовая база может просто удалить библиотеку прокладок и продолжить, в то время как нерасширенный должен выбрать между основным рефактором или постоянно нестандартную и статическую библиотеку утилиты ».

1

Я думаю, это ваш вопрос:

как мы обновляя индексы массива объекта вместе с его имуществом длины при изменении свойства, добавлены или удалены?

Вы создаете методы для этого, поэтому вы по существу имитируете Object internal methods. Я не думаю, что вы можете сделать это с помощью геттеров и сеттеров, но я могу ошибаться в этом.

Остальное - скорее комментарий, чем ответ.

Я давно был готов, чтобы получить линию между родными Массивами и регулярными объектами полностью размыт

линия уже полностью размыта. Массивы - это объекты, единственное, что их отличает, - это свойство специальной длины.

ECMAScript 5, по-видимому, предварительно опорожнить эту тенденцию путем введения шаблонного метода,

ES5 не ввести общие методы, они были на языке, так как ред 3, по крайней мере.

определяется одним типом, но полезной любым

Вовсе нет, на самом деле ES5 является более ограничительным. В ed 3, call и apply принуждение thisArg к объекту с использованием Object(*thisArg*) или заменить глобальный объект, если ничего не было передано. Не так в ES5, который проходит thisArg немодифицированный.

Ограничение использования массивов как объектов связано с конвенцией, а не с самим языком. Большинство разработчиков видят четкий разрыв между тем, когда следует использовать объект или массив. Есть несколько случаев, когда вам действительно нужно использовать массив как объект, но, без сомнения, они существуют. jQuery - пример того, где Объект использует свойства Array, например. элементы, собранные селектором, добавляются как числовые свойства, и существует свойство length, которое представляет собой число элементов. Таким образом, общие методы массива могут быть применены к объектам jQuery (кстати, все это в ed 3).

Метод Object.watch в JavaScrpit ™, это не часть ES5, поэтому используйте его с осторожностью.

Основная проблема с созданием собственной версии встроенных объектов заключается в том, что вы, вероятно, закончите перенос каждого встроенного метода в свой собственный (например, jQuery обертывает каждый метод DOM) и начните установку геттеров и настраивает на каждое свойство или в итоге вызывает вызовы функций для замены доступа к свойствам (например, методы jQuery's val, attr и prop). Довольно утомительно и медленно, если производительность имеет значение.

Ой извините, я уже JQuery ... :-(

Это только кажется, что более целесообразно разработать библиотеку или рамки, чтобы наилучшим образом использовать функции, что язык имеет, а не пытаться заставить его делать что-то нехорошо или не делает изначально.

Но полные отметки для попытки. :-)

+0

Разница между объектами и массивами больше, чем свойство длины массива. Насколько я знаю :-) есть несколько ES5 перечисляемых методов, таких как карта, фильтр добавляется в последние браузеры, однако IE9 также поддерживает его. Эти методы полностью недоступны для родных объектов. –

+0

Вот он: https://github.com/zludany/enumerable.js –

+0

Оба [* 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, они оба «намеренно генерические» не требуют от [их] это значение - объект Array », поэтому они будут работать с любым родным объектом с подходящими свойствами. Они не обязаны работать с объектами хоста (но для объектов DOM во многих браузерах). – RobG