своё замыкание каждому объекту.
Пытаюсь добавить своё собственное замыкание каждому объекту типа Object, но все новые объекты ссылаются на одно и тоже замыкание.
Как заставить объект создавать своё собственное замыкание? код: Object.prototype.key = function(key){ // замыкание var _private = (function(){ var self = this; // set pointer to zero if it's not defined yet if (typeof(self.pointer) === 'undefined') self.pointer = 0; // define setter & getter functions var setter = function(a){self.pointer = a;} var getter = function(){return self.pointer;} // return functions from clouser return {set: setter, get: getter}; })(); // поставить переменную в замыкание if (!!key) _private.set(key); // вернуть переменную из замыкания return _private.get(); } var FirstObject = {}; // set private value for first object FirstObject.key(100); var SecondObject = {}; // set private value for second object SecondObject.key(999); // возвращает 999, а не 100 alert(FirstObject.key()); |
Потому что this === window
|
Цитата:
|
Да и вообще, чего так мудрить-то?:)
Object.prototype.key = function(key){ if (typeof(this.pointer) === 'undefined') this.pointer = 0; if (!!key) this.pointer = key; return this.pointer; } var FirstObject = {}, SecondObject = {}; FirstObject.key(100); SecondObject.key(999); alert(FirstObject.key()); |
Цитата:
|
Sweet:
Весь вопрос возник исключительно из интереса возможности реализации :-) Если this === window, то как сослаться на текущее замыкание? Я пробую создать приватное свойство, которое не должно засорять свойства объекта, доступ должен быть исключительно из тела функции. |
Kolyaj:
Можно ли обойтись без прототипов и объявления переменной как свойства объекта, чтобы не убивать котёнка? :-) |
В JS нет приватных свойств, и не надо.
|
Kolyaj:
Ну если Вы не знаете как решить поставленную задачу, зачем мешать? |
Object.prototype.key = function(key){ *!*var self = this;*/!* //Вынеси self из _private, чтобы сделать ссылку на объект // замыкание var _private = (function(){ // set pointer to zero if it's not defined yet if (typeof(self.pointer) === 'undefined') self.pointer = 0; // define setter & getter functions var setter = function(a){self.pointer = a;} var getter = function(){return self.pointer;} // return functions from clouser return {set: setter, get: getter}; })(); // поставить переменную в замыкание if (!!key) _private.set(key); // вернуть переменную из замыкания return _private.get(); } var FirstObject = {}; // set private value for first object FirstObject.key(100); var SecondObject = {}; // set private value for second object SecondObject.key(999); // возвращает 999, а не 100 alert(FirstObject.key()); |
cainrus,
не хотите делать так, как принято в языке, на котором пишете, можете просто игнорировать мои сообщения. |
Sweet,
pointer теперь в зоне видимости и к нему открытый доступ через FirstObject.pointer |
Kolyaj:
Вы говорите не о том как принято в языке, а о том как удобно разработчикам, потому что Вам не нравятся какие-то "костыли". в php тоже были костыли для нереализованных возможностей языка, затем некоторые костыли реализовали. А в javascript слово private зарезервировано для будущего использования, т.е. это говорит о том, что возможно это когда-то будет реализовано и принято. |
Цитата:
|
Вот, навскидку:
Object.prototype.key = (function(){ var storage = [], _undefined; return function(value){ if(value!=_undefined){ for(var i=0; i<storage.length; i++) if(storage[i].object==this){ storage[i].value = value; return value; } storage.push({object:this,value:arguments[0]}); return value; } for(var i=0; i<storage.length; i++) if(storage[i].object==this) return storage[i].value; return _undefined; } }()) var FirstObject = {}, SecondObject = {}; FirstObject.key(100); SecondObject.key(999); alert([FirstObject.key(), SecondObject.key()]); |
Sweet:
Удивляюсь как вы до этого дошли. Работает так как требовалось. Первоначально я всего лишь хотел реализовать функционал для массива как в php: next, prev, current, end, reset, key. Всё застопорилось, когда я обнаружил, что внутренний указатель во всех массивах везде одинаков. |
Sweet,
Вопрос а если value = 0 ? FirstObject.key(0)=null а надо наверно FirstObject.key(0)=0. Вопрос к желающим как правильно сделать проверку наличия агрумента у функции? |
Цитата:
Цитата:
|
Цитата:
http://alljs.ru/articles/undefined.html#args |
Цитата:
|
А как тогда присвоить undefined? Этакое обнуление свойства.
|
Обnullять можно присваивая null:) Но по уму тут нужно не "обнулять" значение, а выдергивать весь объект из массива storage: если он пустой (undefined), то и незачем по нему пробегать в цикле for.
|
я в Вашем примере кода, попробовал не заталкивать с помощью "push" значения в массив, а использовать storage как объект, в который по ключу ставить значения:
storage[this] = newValue; Это избавило меня от лишнего цикла. Для меня оказалось удивительным то, что this используемый как ключ, оказался уникальным, когда его (this) используешь в едином замыкании для всех объектов, даже если объекты по существу будут одинаковыми(но не ссылками друг на друга). |
cainrus, покажи, пожалуйста, рабочий пример:)
Вообще, ключ в объекте, если кто не в курсе, - строка. Так что же ввело в заблуждение? var object = {}, innerObject = {}; object[innerObject] = {prop: 'value'}; alert(object[innerObject].prop); // value var string = innerObject.toString(); // [object Object] alert(object[string].prop); // value // А вот, что происходит на самом деле: alert(object['[object Object]'].prop); // value |
Кстати, вариант storage[this] = newValue; вполне возможен. Правда, придется залезть не только в Object.prototype, но и в метод toString. Учтите, Kolyaj не даст соврать, при этом бог убьет не только котенка, но и щеночка. Поэтому вариант с циклом мне более симпатичен:)
Object.prototype.key = (function(){ var storage = {}, count = 0; return function(value){ if(this.toString()=='[object Object]') this.toString=(function(){ var string = 'obj'+count; count++; return function(){return string;}; }()); if(arguments.length!=0){ storage[this] = value; return value; }; return storage[this]; }; }()); var FirstObject = {a:1}, SecondObject = {b:2}; FirstObject.key(100); SecondObject.key(999); alert([FirstObject.key(), SecondObject.key()]); |
Да, я обнаружил что мой код не работает правильно, когда посмотрел метод toString(). Если есть два массива с одинаковым наполнением, то ключ хранения между ними будет общий, а если хранить объекты в массиве, тогда баг проявится при одинаковом количестве объектов в массиве.
// Extending Array Object Array.prototype.key = (function(){ var storage = []; return function(key){ if ( typeof(key) !== "undefined" ) { // Add positive number or null, if key presents, and return self instance. key = parseInt(key); // If key is invalid or out of range, then it should be null. if (key < 0 || key > this.length - 1 || isNaN(key)) key = null; storage[this] = key; return this; } else { // Return key key = storage[this]; // If key is undefined, then it should be null. if (typeof(key) === "undefined") key = null; return key; } // Get value; if value is not defined, then set it to null. if (typeof(value = storage[this]) === "undefined") value = null; // Return index of array or null if array is empty return value; } }()); // Let's test two new arrays SomeArray = [1,2,3,4,5,6,7,8,9]; AnotherArray = ['a','b','c','d','e','f','g']; BonusArray = ['a','b','c','d','e','f','g']; // key method should return key index alert('SomeArray key = '+SomeArray.key()); //null, there is no index yet SomeArray.key(2); // set first array index to 2 AnotherArray.key(5); // set second array index to 5 alert('SomeArray key = '+SomeArray.key()); // 2 ! alert('AnotherArray key = '+AnotherArray.key()); // 5 ! alert('BonusArray key = '+BonusArray.key()); // 5 ! but it should not.. Перепишу фишку, используя первоначальный способ с циклом, раз нет других способов :) |
Не, ты явно не понял сути конструкции типа storage[this]!!!
Вот смотри, почему у тебя возникает "баг" (это не баг, просто функция криво написана): Когда ключ - объект, он приводится к строке методом toString(). У массива в таком случае возвращается строка со значениями через запятую. Так вот что у тебя происходит. alert('SomeArray key = '+SomeArray.key()); //функция смотрит storage['1,2,3,4,5,6,7,8,9']. Его нет. SomeArray.key(2); //функция устанавливает storage['1,2,3,4,5,6,7,8,9'] = 2 AnotherArray.key(5); //устанавливает storage['a,b,c,d,e,f,g'] = 5 alert('SomeArray key = '+SomeArray.key()); //смотрим storage['1,2,3,4,5,6,7,8,9']. Там значение 2 alert('AnotherArray key = '+AnotherArray.key()); //смотрим storage['a,b,c,d,e,f,g']. Там значение 5 alert('BonusArray key = '+BonusArray.key()); //BonusArray.toString() = 'a,b,c,d,e,f,g'. //смотрим storage['a,b,c,d,e,f,g']. Там значение 5 //Вот и весь "баг" |
да, я понял это когда прочитал про функцию toString.
Сначала ошибочно посчитал(не проверил), что this должен преобразоваться в [Object Object](когда я его использую в качестве индекса массива), но раз ошибок не возникало(не проверял одинаково наполненные массивы), посчитал что действительно объекты помещаются в индексы(вот глупость!). Если бы я наполнял массивы объектами, то выявил бы ошибку ещё раньше, надеюсь понятно почему :-) но, спасибо за твоё время. |
в нормальных языках объекты вполне можно использовать в качестве ключей.
|
Цитата:
|
тут вот у меня описывается ObjectHash, позволяющий в качестве ключей использовать объекты: http://javascript.ru/blog/tenshi/yavascriptovoe-dao
|
а вообще, сабж элементарно делается так:
Object.prototype.key= function(){ return ( this.key= FProp( 0 ) ).apply( this, arguments ) } http://github.com/sairi-na-tenshi/wc...ster//FProp.js http://github.com/sairi-na-tenshi/wc...ster//FPoly.js |
2tenshi:
github( не могу в нём освоиться ещё.. ) не открывает ссылки, да и вообще, я мог бы давно уже воспользоваться дополнительными сторонними библиотеками или просто использовать более тяжёлые решения. Пришла идея, добавлять через eval при создании массива функцию(например, geUid), которая будет возвращать уникальный идентификатор. Функцию geUid хорошо бы держать внутри метода .key возвращающего ключ( [1,2,3].key() ), чтобы не захламлять внутреннее пространство объекта массива внутренне-вспомогательными методами(geUid). Тогда придется генерировать весь метод key при создании нового массива. Понравилась идея про выделение объекта итератора из самого массива как отдельную сущность. Попробую осуществить каким-нибудь простым способом.. Эта идея избавляет меня от многих проблем описанных в топике( и посте ), а также от раздутия новыми методами объекта массива. Ну, начну играть с кодом :write: |
поправил ссылки. это не библиотеки. это пара маленьких функций.
|
Вот то что получилось в итоге:
Array.iterator.js оформил как плагин под mootools, если кто может посмотреть и сказать где плохо, грязно, некрасиво, криво, буду рад исправить. демо алгоримта работы в виде галереи. и маленькое описание. |
я бы сделал next и prev алиасами для slide со значением 1 по умолчанию и вычитанием из нуля в случае prev. не хватает метода count. возможности указывать смещение для jump не только сначала массива, но и с конца (отрицательным значением). неплохо было бы иметь возможность итерироваться не по всему массиву, а только по его диапазону. например: [1,2,3,4,5].iterator( range: [ 1, -1 ] ) // будет итерировать только с 2 по 4, по умолчанию range=[ 0, 0 ] то есть итерирование по всему массиву
|
почему ты хранишь текущий ключ не в итераторе, а в глобальном реестре?
|
аналогично со ссылкой на массив - зачем хранить её в замыкании?
|
зачем в slide регулярка? достаточно просто привести к типу Number
|
tenshi,
Ссылка на массив защищена в замыкании, потому что массив рождает итератор не позволяя потомку(итератору) переопределить ссылку с себя на другой массив. Массив может иметь несколько итераторов, а не наоборот. Ключ храню в замыкании, потому что он всегда должен обеспечивать точные данные, которые можно было бы случайно подменить, если не скрыть его, а оставить внутри итератора как свойство объекта. Замыкание глобальное для всех итераторов, чтобы съэкономить ресурсы, если вздумается создать сотенку итераторов. Эти 2 замыкания помогут избежать ошибок. Диапазон итерирования был оставлен как домашнее задания для самого себя же в секции TODO скрипта)) Зачем нужен метод "count"? он ведь не относится к итерации. |
Часовой пояс GMT +3, время: 05:20. |