Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 02.09.2012, 20:01
Аватар для FINoM
Новичок
Отправить личное сообщение для FINoM Посмотреть профиль Найти все сообщения от FINoM
 
Регистрация: 05.09.2010
Сообщений: 2,298

Борьба с Object.defineProperty в IE8
Мне сегодня пришла такая мысль: почему мы не хотим использовать ноды в качестве объектов? Потому что в объекте будут иметься левые свойства. Чем это чревато?
1. При перечислении с помощью for..in будем получать кучу левых свойств.
2. При сериализации стандартными методами JSON будем получать undefined.

Первое решается созданием функции-итератора (например, какой-нибудь each), второе — написанием собственной функции для сериализации.

Что было выяснено, во время экспериментов:
1. Если дескриптор содержит value, enumerable не может равняться false.
2. И наоборот, если дескриптор содержит get или set, enumerable: true не работает.

3. configurable: false не работает при любом раскладе.
4. writable: false не работает при наличии value (ну и, конечно с аццессорами, так как не может работать по спецификации, хотя к чему я тут упоминаю спецификации...).

Удалось побороть всё, кроме второго (такое свойство не попадает в for..in, но работает с функцией each).

Вот, что сделал на скорую руку (см., начиная с 154 строки):

Борьба с Object.defineProperty в IE8 — версия по-красивее
( function() {
	if (!Array.prototype.indexOf) {
		Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
			"use strict";
			if (this == null) {
				throw new TypeError();
			}
			var t = Object(this);
			var len = t.length >>> 0;
			if (len === 0) {
				return -1;
			}
			var n = 0;
			if (arguments.length > 1) {
				n = Number(arguments[1]);
				if (n != n) { // shortcut for verifying if it's NaN
					n = 0;
				} else if (n != 0 && n != Infinity && n != -Infinity) {
					n = (n > 0 || -1) * Math.floor(Math.abs(n));
				}
			}
			if (n >= len) {
				return -1;
			}
			var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
			for (; k < len; k++) {
				if (k in t && t[k] === searchElement) {
					return k;
				}
			}
			return -1;
		}
	}
	
	var extend = function( o1, o2 ) {
		for( var i in o2 ) {
			o1[ i ] = o2[ i ];
		}
	};
	
	
	
	var initIeObject = function() {
		JSON._stringify = JSON.stringify;
		JSON.stringify = function( object ) {
			var props = object._enumerableProps,	
				o;
			if( props ) {
				o = {}
				for( var i = 0; i < props.length; i++ ) {
					o[ props[ i ] ] = object[ props[ i ] ];
				}
			} else {
				o = object;
			}
			return JSON._stringify( o );
		};
		Object.defineProperties = function( object, descriptors ) {
			for( var key in descriptors ) {
				Object.defineProperty( object, key, descriptors[ key ] );
			}
		};
		Object._defineProperty = Object.defineProperty;
		Object.defineProperty = function( object, key, descriptor ) {
			var isConfugurable = descriptor.configurable !== undefined ? descriptor.configurable : false ;
			
			object._enumerableProps = object._enumerableProps || [];
			object._notEnumerableProps = object._notEnumerableProps || [];
			
			if( object._notConfigutable && ~object._notConfigutable.indexOf( key ) ) {
				throw TypeError( 'Cannot redefine property: ' + key );
			}
			
			
			delete descriptor.configurable;
			if( descriptor.enumerable === false ) {
				if( 'value' in descriptor ) {
					// фикс
					object[ '_' + key ] = descriptor.value;
					Object._defineProperty( object, key, {
						get: function() {
							return this[ '_' + key ];
						},
						set: function( value ) {
							this[ '_' + key ] = value;
						}
					});
					if( descriptor.writable === false ) {
						Object._defineProperty( object, key, {
							get: function() {
								return descriptor.value;
							}
						});
					}
				} else {
					Object._defineProperty( object, key, descriptor );
				}
				object._notEnumerableProps.push( key );
				
			} else {
				if( 'get' in descriptor || 'set' in descriptor ) {
					// что здесь можно сделать, чтоб свойство перечислялось с помощью for..in?
					descriptor.enumerable === false;
					Object._defineProperty( object, key, descriptor );
				} else {
					Object._defineProperty( object, key, descriptor );
				}
				
				object._enumerableProps.push( key );
			}
			
			if( isConfugurable === false ) {
				object._notConfigutable = object._notConfigutable || [];
				object._notConfigutable.push( key );
			}
		};
		
		Object.getOwnPropertyNames = function( object ) {
			return object._enumerableProps.concat( object._notEnumerableProps );
		};
		
		Object.keys = function( object ) {
			return object._enumerableProps;
		};
		
		Object.create = function( prototype, descriptors ) {
			var object = document.createComment( '' );
			document.body.appendChild( object );
			prototype && extend( object, prototype );
			Object.defineProperties( object, descriptors );
			object.hasOwnProperty = function( key ) { // можно эту штуку использовать в for..in, но свойства с аццессорами перечисляться не будут
				return !!~Object.getOwnPropertyNames( object ).indexOf( key );
			}
			return object;
		}
	}
	if( !Object.create && Object.defineProperty ) { 
		initIeObject();
	}
})();

var each = function( object, callback ) {
		var props = object._enumerableProps;
		if( props ) {
			for( var i = 0; i < props.length; i++ ) {
				callback.call( object[ props[ i ] ], props[ i ], object[ props[ i ] ]  );
			}
		} else {
			for( var i in object ) if( object.hasOwnProperty( i ) ) {
				callback.call( object[ i ], i, object[ i ] );
			}
		}
	}

x = Object.create( Object.prototype, {a: { value: 1, enumerable: true } });
console.log( x.a );
for( var i in x ) if( x.hasOwnProperty( i ) ){ console.log( i ) };


//Журнал: 1 
//Журнал: a 

y = Object.create( Object.prototype );
Object.defineProperties( y, {
	b: {
		get: function() {
			return 2;
		},
		set: function( value ) {
			alert( 'y.b setter, value = ' + value )
		},
		configurable: true
	},
	c: {
		get: function() {
			return 3;
		},
		set: function( value ) {
			alert( 'y.c setter, value = ' + value )
		}
	},
	d: {
		value: 4,
		configurable: false
	},
	e: {
		value: 5,
		enumerable: false,
		writable: false
	}
});

each( y, function( key, value ) {
	console.log( key,  ' ', value )
});

//Журнал: b 2 
//Журнал: c 3 
//Журнал: d 4 

console.log( JSON.stringify( y ) );
//Журнал: {"b":2,"c":3,"d":4} 

Object.defineProperty( y, 'b', { get: function() { return 'changed B' }});
console.log( y.b );
//Журнал: changed B 

console.log( 'e ', y.e );
//Журнал: e 5 
y.e = 123;
console.log( 'e ', y.e );

//Журнал: e 5 
Object.defineProperty( y, 'd', { get: function() { return 'changed D' }});
console.log( y.d );
//Error "Cannot redefine property: d"


Можно поиграться в консоли.
__________________
"Matreshka is fucking awesome" © чувак с Reddit
Matreshka.js - Три возможности

Последний раз редактировалось FINoM, 03.09.2012 в 05:49.
Ответить с цитированием
  #2 (permalink)  
Старый 02.09.2012, 20:38
Аватар для FINoM
Новичок
Отправить личное сообщение для FINoM Посмотреть профиль Найти все сообщения от FINoM
 
Регистрация: 05.09.2010
Сообщений: 2,298

Так-с, почти всё поборол. Если заставить свойство с аццессорами перечисляться через for..in, то, при использовании hasOwnProperty (а его ведь все используют, не так ли?) может даже показаться, что мы работаем с обычным объектом.

Не пинайте за говнокод, это лишь прототип.
__________________
"Matreshka is fucking awesome" © чувак с Reddit
Matreshka.js - Три возможности
Ответить с цитированием
  #3 (permalink)  
Старый 02.09.2012, 20:45
что-то знаю
Отправить личное сообщение для devote Посмотреть профиль Найти все сообщения от devote
 
Регистрация: 24.05.2009
Сообщений: 5,176

Сообщение от FINoM
hasOwnProperty (а его ведь все используют, не так ли?)
все верно, но я обычно юзаю его так:
Object.prototype.hasOwnProperty.call( obj, prop );
уж простите но привычка)))
__________________
хм Russians say завтра but завтра doesn't mean "tomorrow" it just means "not today."
HTML5 history API рассширение для браузеров не поддерживающих pushState, replaceState
QSA CSS3 Selector Engine
Ответить с цитированием
  #4 (permalink)  
Старый 02.09.2012, 20:51
Аватар для Gozar
Отправить личное сообщение для Gozar Посмотреть профиль Найти все сообщения от Gozar
 
Регистрация: 07.06.2007
Сообщений: 7,504

Поддерживать всякое убожество аля IE6789, в бесплодной попытке продлить ему жизнь?! Всё равно оно никогда не дорастет до нынешних FF, Chrome, Opera. Во фронтэнде использовать новые фичи клепая миллион заплаток?

ИМХО я пишу в двух стилях: совместимый(библиотека+) и нормальный код.

А так идея конечно интересная, буду ждать продолжения.
__________________
Последний раз редактировалось Gozar, Сегодня в 24:14.
Ответить с цитированием
  #5 (permalink)  
Старый 02.09.2012, 20:51
Аватар для FINoM
Новичок
Отправить личное сообщение для FINoM Посмотреть профиль Найти все сообщения от FINoM
 
Регистрация: 05.09.2010
Сообщений: 2,298

Сообщение от devote
все верно, но я обычно юзаю его так
Эм, а смысл?
__________________
"Matreshka is fucking awesome" © чувак с Reddit
Matreshka.js - Три возможности
Ответить с цитированием
  #6 (permalink)  
Старый 02.09.2012, 20:53
Аватар для FINoM
Новичок
Отправить личное сообщение для FINoM Посмотреть профиль Найти все сообщения от FINoM
 
Регистрация: 05.09.2010
Сообщений: 2,298

Сообщение от Gozar
Поддерживать всякое убожество аля IE6789, в бесплодной попытке продлить ему жизнь?!
Лично у меня задача перенести через несколько месяцев проект, в котором очень активно используется defineProperty с гетерами и сеттерами. Как это сделать, не переписывая полностью, от начала до конца, я не знаю.
__________________
"Matreshka is fucking awesome" © чувак с Reddit
Matreshka.js - Три возможности
Ответить с цитированием
  #7 (permalink)  
Старый 02.09.2012, 20:55
что-то знаю
Отправить личное сообщение для devote Посмотреть профиль Найти все сообщения от devote
 
Регистрация: 24.05.2009
Сообщений: 5,176

Сообщение от FINoM
Эм, а смысл?
что бы GCC сжал лучшее, объявляю один раз:
(function( global ){
    var hasOwnProperty = Object.prototype.hasOwnProperty;

    // много кода

    // и где то
    for( ... ) {
        if ( hasOwnProperty.call( o, prop ) ) {
            // ....
        }
    }

    // и еще где то
    for( ... ) {
        if ( hasOwnProperty.call( o, prop ) ) {
            // ....
        }
    }

})( window );
GCC такой код сожмет лучшее превратив его примерно в:
(function( g ){
    var h = Object.prototype.hasOwnProperty;

    // много кода

    // и где то
    for( ... ) {
        if ( h.call( o, p ) ) {
            // ....
        }
    }

    // и еще где то
    for( ... ) {
        if ( h.call( o, p ) ) {
            // ....
        }
    }

})( window );
__________________
хм Russians say завтра but завтра doesn't mean "tomorrow" it just means "not today."
HTML5 history API рассширение для браузеров не поддерживающих pushState, replaceState
QSA CSS3 Selector Engine
Ответить с цитированием
  #8 (permalink)  
Старый 02.09.2012, 21:19
Аватар для FINoM
Новичок
Отправить личное сообщение для FINoM Посмотреть профиль Найти все сообщения от FINoM
 
Регистрация: 05.09.2010
Сообщений: 2,298

Запустил код из поста в хроме, получил ошибку. Почему при создании объекта через Object.create, метод hasOwnProperty отсутствует? Мы ведь наследуем прототип Object.
x = Object.create( null )
x.hasOwnProperty( 'a' )
__________________
"Matreshka is fucking awesome" © чувак с Reddit
Matreshka.js - Три возможности
Ответить с цитированием
  #9 (permalink)  
Старый 02.09.2012, 21:25
Аватар для nerv_
junior
Отправить личное сообщение для nerv_ Посмотреть профиль Найти все сообщения от nerv_
 
Регистрация: 29.11.2011
Сообщений: 3,924

FINoM, можно комментарий?
Сообщение от FINoM
t.length >>> 0;
видел где-то, но не помню, что это (кажется какой-то хак)

Сообщение от Gozar
Поддерживать всякое убожество аля IE6789, в бесплодной попытке продлить ему жизнь?! Всё равно оно никогда не дорастет до нынешних FF, Chrome, Opera. Во фронтэнде использовать новые фичи клепая миллион заплаток?
мое мнение: лучше их убить побыстрей
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук

Последний раз редактировалось nerv_, 02.09.2012 в 21:28.
Ответить с цитированием
  #10 (permalink)  
Старый 02.09.2012, 21:27
Аватар для FINoM
Новичок
Отправить личное сообщение для FINoM Посмотреть профиль Найти все сообщения от FINoM
 
Регистрация: 05.09.2010
Сообщений: 2,298

nerv_, этот код сперт с MDN.
__________________
"Matreshka is fucking awesome" © чувак с Reddit
Matreshka.js - Три возможности
Ответить с цитированием
Ответ


Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
JSON.stringify в IE8 sysif Internet Explorer 13 15.02.2012 09:11
ExtJS theming в IE8!? JDev ExtJS 0 05.01.2012 15:56
window.resizeTo(w,h) в ie8 задёт не те размеры. mister_maxim Internet Explorer 1 29.07.2011 22:51
Как отключить режим совместимости в IE8? kidar2 Internet Explorer 2 25.06.2011 16:45
<= IE8 memory leak, IE9 - fine AbNormy Internet Explorer 1 20.05.2011 19:47