Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   своё замыкание каждому объекту. (https://javascript.ru/forum/misc/12103-svojo-zamykanie-kazhdomu-obektu.html)

cainrus 30.09.2010 17:07

своё замыкание каждому объекту.
 
Пытаюсь добавить своё собственное замыкание каждому объекту типа 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());

Sweet 30.09.2010 17:22

Потому что this === window

Kolyaj 30.09.2010 17:28

Цитата:

Сообщение от cainrus
Object.prototype.key

Когда вы добавляете что-то своё в Object.prototype, бог убивает котёнка.

Sweet 30.09.2010 17:29

Да и вообще, чего так мудрить-то?:)
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 30.09.2010 17:29

Цитата:

Сообщение от Kolyaj
Когда вы добавляете что-то своё в Object.prototype, бог убивает котёнка.

:haha: Жжешь!

cainrus 30.09.2010 17:38

Sweet:
Весь вопрос возник исключительно из интереса возможности реализации :-)

Если this === window, то как сослаться на текущее замыкание?
Я пробую создать приватное свойство, которое не должно засорять свойства объекта, доступ должен быть исключительно из тела функции.

cainrus 30.09.2010 17:42

Kolyaj:
Можно ли обойтись без прототипов и объявления переменной как свойства объекта, чтобы не убивать котёнка? :-)

Kolyaj 30.09.2010 17:46

В JS нет приватных свойств, и не надо.

cainrus 30.09.2010 17:48

Kolyaj:
Ну если Вы не знаете как решить поставленную задачу, зачем мешать?

Sweet 30.09.2010 17:56

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());

Kolyaj 30.09.2010 17:59

cainrus,
не хотите делать так, как принято в языке, на котором пишете, можете просто игнорировать мои сообщения.

cainrus 30.09.2010 18:07

Sweet,
pointer теперь в зоне видимости и к нему открытый доступ через
FirstObject.pointer

cainrus 30.09.2010 18:13

Kolyaj:
Вы говорите не о том как принято в языке, а о том как удобно разработчикам, потому что Вам не нравятся какие-то "костыли".
в php тоже были костыли для нереализованных возможностей языка, затем некоторые костыли реализовали.
А в javascript слово private зарезервировано для будущего использования, т.е. это говорит о том, что возможно это когда-то будет реализовано и принято.

Sweet 30.09.2010 18:25

Цитата:

Сообщение от cainrus
pointer теперь в зоне видимости и к нему открытый доступ через FirstObject.pointer

Это вполне очевидно:) Я и не понял по-началу, что этого не должно быть:) Это объясняет затеяние:D

Sweet 30.09.2010 18:47

Вот, навскидку:
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()]);

cainrus 30.09.2010 19:17

Sweet:
Удивляюсь как вы до этого дошли. Работает так как требовалось. Первоначально я всего лишь хотел реализовать функционал для массива как в php: next, prev, current, end, reset, key. Всё застопорилось, когда я обнаружил, что внутренний указатель во всех массивах везде одинаков.

рони 01.10.2010 10:46

Sweet,
Вопрос а если value = 0 ? FirstObject.key(0)=null а надо наверно FirstObject.key(0)=0.
Вопрос к желающим как правильно сделать проверку наличия агрумента у функции?

Sweet 01.10.2010 11:44

Цитата:

Сообщение от рони
Вопрос к желающим

??? К Каким желающим?:)
Цитата:

Сообщение от рони
как правильно сделать проверку наличия агрумента у функции?

Проверить свойство arguments.length либо typeof arguments[0] != 'undefined'.

Kolyaj 01.10.2010 12:24

Цитата:

Сообщение от Sweet
Проверить свойство arguments.length либо typeof arguments[0] != 'undefined'.

Никаких либо.

http://alljs.ru/articles/undefined.html#args

Sweet 01.10.2010 12:56

Цитата:

Сообщение от Kolyaj
Никаких либо.

Почему так категорично?:) Я специально сделал именно typeof != 'undefined', потому что в данном случае по-моему неоправданным считать 'undefined' за аргумент. Ведь это же не хранилище неопределенности:)

Kolyaj 01.10.2010 13:45

А как тогда присвоить undefined? Этакое обнуление свойства.

Sweet 01.10.2010 13:59

Обnullять можно присваивая null:) Но по уму тут нужно не "обнулять" значение, а выдергивать весь объект из массива storage: если он пустой (undefined), то и незачем по нему пробегать в цикле for.

cainrus 02.10.2010 05:17

я в Вашем примере кода, попробовал не заталкивать с помощью "push" значения в массив, а использовать storage как объект, в который по ключу ставить значения:
storage[this] = newValue;


Это избавило меня от лишнего цикла.
Для меня оказалось удивительным то, что this используемый как ключ, оказался уникальным, когда его (this) используешь в едином замыкании для всех объектов, даже если объекты по существу будут одинаковыми(но не ссылками друг на друга).

Sweet 02.10.2010 10:26

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

Sweet 02.10.2010 11:34

Кстати, вариант 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()]);

cainrus 02.10.2010 17:11

Да, я обнаружил что мой код не работает правильно, когда посмотрел метод 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..


Перепишу фишку, используя первоначальный способ с циклом, раз нет других способов :)

Sweet 02.10.2010 19:05

Не, ты явно не понял сути конструкции типа 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
//Вот и весь "баг"

cainrus 03.10.2010 00:13

да, я понял это когда прочитал про функцию toString.

Сначала ошибочно посчитал(не проверил), что this должен преобразоваться в [Object Object](когда я его использую в качестве индекса массива), но раз ошибок не возникало(не проверял одинаково наполненные массивы), посчитал что действительно объекты помещаются в индексы(вот глупость!).
Если бы я наполнял массивы объектами, то выявил бы ошибку ещё раньше, надеюсь понятно почему :-) но, спасибо за твоё время.

tenshi 04.10.2010 22:42

в нормальных языках объекты вполне можно использовать в качестве ключей.

tenshi 04.10.2010 22:44

Цитата:

Сообщение от cainrus (Сообщение 72559)
Sweet:
Удивляюсь как вы до этого дошли. Работает так как требовалось. Первоначально я всего лишь хотел реализовать функционал для массива как в php: next, prev, current, end, reset, key. Всё застопорилось, когда я обнаружил, что внутренний указатель во всех массивах везде одинаков.

не надо так делать. это глупо. сделай так, чтобы массив возвращал итератор, у которого уже будут эти методы

tenshi 04.10.2010 22:49

тут вот у меня описывается ObjectHash, позволяющий в качестве ключей использовать объекты: http://javascript.ru/blog/tenshi/yavascriptovoe-dao

tenshi 04.10.2010 23:02

а вообще, сабж элементарно делается так:

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

cainrus 13.10.2010 06:04

2tenshi:
github( не могу в нём освоиться ещё.. ) не открывает ссылки, да и вообще, я мог бы давно уже воспользоваться дополнительными сторонними библиотеками или просто использовать более тяжёлые решения.

Пришла идея, добавлять через eval при создании массива функцию(например, geUid), которая будет возвращать уникальный идентификатор.
Функцию geUid хорошо бы держать внутри метода .key возвращающего ключ( [1,2,3].key() ), чтобы не захламлять внутреннее пространство объекта массива внутренне-вспомогательными методами(geUid). Тогда придется генерировать весь метод key при создании нового массива.

Понравилась идея про выделение объекта итератора из самого массива как отдельную сущность. Попробую осуществить каким-нибудь простым способом.. Эта идея избавляет меня от многих проблем описанных в топике( и посте ), а также от раздутия новыми методами объекта массива. Ну, начну играть с кодом :write:

tenshi 13.10.2010 12:36

поправил ссылки. это не библиотеки. это пара маленьких функций.

cainrus 22.10.2010 06:10

Вот то что получилось в итоге:

Array.iterator.js

оформил как плагин под mootools,
если кто может посмотреть и сказать где плохо, грязно, некрасиво, криво, буду рад исправить.

демо алгоримта работы в виде галереи.
и маленькое описание.

tenshi 22.10.2010 13:56

я бы сделал next и prev алиасами для slide со значением 1 по умолчанию и вычитанием из нуля в случае prev. не хватает метода count. возможности указывать смещение для jump не только сначала массива, но и с конца (отрицательным значением). неплохо было бы иметь возможность итерироваться не по всему массиву, а только по его диапазону. например: [1,2,3,4,5].iterator( range: [ 1, -1 ] ) // будет итерировать только с 2 по 4, по умолчанию range=[ 0, 0 ] то есть итерирование по всему массиву

tenshi 22.10.2010 14:01

почему ты хранишь текущий ключ не в итераторе, а в глобальном реестре?

tenshi 22.10.2010 14:02

аналогично со ссылкой на массив - зачем хранить её в замыкании?

tenshi 22.10.2010 14:06

зачем в slide регулярка? достаточно просто привести к типу Number

cainrus 23.10.2010 03:20

tenshi,

Ссылка на массив защищена в замыкании, потому что массив рождает итератор не позволяя потомку(итератору) переопределить ссылку с себя на другой массив.
Массив может иметь несколько итераторов, а не наоборот.

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

Эти 2 замыкания помогут избежать ошибок.

Диапазон итерирования был оставлен как домашнее задания для самого себя же в секции TODO скрипта))

Зачем нужен метод "count"? он ведь не относится к итерации.


Часовой пояс GMT +3, время: 05:20.