Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   Борьба с Object.defineProperty в IE8 (https://javascript.ru/forum/offtopic/31305-borba-s-object-defineproperty-v-ie8.html)

FINoM 03.09.2012 01:27

Очень жаль, что нельзя так сделать:
var s = new XDomainRequest;
F = function() {}
F.prototype = s;
f = new F;
Object.defineProperty( s, 'x', {get: function() {return 123}, set: function() { alert() }, enumerable: false} );

console.log( f.x ); // ← undefined

FINoM 03.09.2012 02:16

Так-с, продолжаю раскопки. XDomainRequest.prototype содержит всего три свойства и так же позволяет использовать дескрипторы:
var s = XDomainRequest.prototype;
Object.defineProperty( s, 'blahblah', {value: 1} );
for( var i in s ) {
	console.log( i );
}
console.log( s );
console.log( s.constructor );

Журнал: open 
Журнал: send 
Журнал: abort 
Журнал: blahblah 
Журнал: [Interface prototype object] 
Журнал: null
Как видно, свойство constructor === null. Мот кто в курсе, где нарыть это самый Interface prototype конструктор?

FINoM 03.09.2012 02:38

Судя по всему таки нет никакого конструктора, а такая штука не катит и не наследует свойства:
F = function() {}
F.prototype = XDomainRequest.prototype;
f = new F;

Aetae 03.09.2012 03:26

Продолжайте, продолжайте, весьма увлекательно.))

FINoM 03.09.2012 04:46

Совсем немного отрефакторил код. Теперь итератором служит кастомный метод Object.each, который работает для всех браузеров, у которых есть defineProperty (то есть целевых браузеров).

В итоге у нас есть методы:
Object.defineProperties
Object.getOwnPropertyNames
Object.keys
Object.create
Object.getOwnPropertyDescriptor
Object.each — нестандартный

for..in всё еще не рекомендуется использовать.
( 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;
		}
	}
	if( !Object.create && Object.defineProperty ) { 
		initIeObject();
	}
	
	
	function initIeObject() {
		var Constructor = XDomainRequest,
			defineProperty = Object.defineProperty,
			getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
			
		Constructor.prototype.hasOwnProperty = function( key ) {
			return !!~Object.getOwnPropertyNames( this ).indexOf( key );
		};
		Object.defineProperties = function( object, descriptors ) {
			for( var key in descriptors ) {
				Object.defineProperty( object, key, descriptors[ key ] );
			}
		};
		JSON._stringify = JSON.stringify;
		JSON.stringify = function( object ) {
			var props = object._settings_ && object._settings_.enumerable,	
				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.defineProperty = function( object, key, descriptor ) {
			if( !( object instanceof Constructor ) ) return defineProperty( object, key, descriptor ); // if another dom object
			
			var isConfugurable = descriptor.configurable !== undefined ? descriptor.configurable : false,
				_settings_ = object._settings_ = object._settings_ || {
					enumerable: [],
					notEnumerable: [],
					notConfigurable: [],
					descriptors: {}
				};
			
			delete descriptor.configurable;
			
			_settings_.descriptors[ key ] = descriptor;
			
			if( ~_settings_.notConfigurable.indexOf( key ) ) {
				throw TypeError( 'Cannot redefine property: ' + key );
			}			
			
			if( descriptor.enumerable === false ) {
				if( 'value' in descriptor ) {
					object[ '___' + key ] = descriptor.value;
					defineProperty( object, key, {
						get: function() {
							return this[ '___' + key ];
						},
						set: function( value ) {
							this[ '___' + key ] = value;
						}
					});
					if( descriptor.writable === false ) {
						defineProperty( object, key, {
							get: function() {
								return descriptor.value;
							}
						});
					}
				} else {
					defineProperty( object, key, descriptor );
				}
				
				_settings_.notEnumerable.push( key );
				
			} else {
				if( 'get' in descriptor || 'set' in descriptor ) {
					// что здесь можно сделать, чтоб свойство перечислялось с помощью for..in?
					descriptor.enumerable === false;
				} 
				
				defineProperty( object, key, descriptor );
				
				_settings_.enumerable.push( key );
			}
			
			if( isConfugurable === false ) {
				_settings_.notConfigurable.push( key );
			}
			
			_settings_.descriptors[ key ].configurable = isConfugurable;
		};
		
		Object.getOwnPropertyNames = function( object ) {
			return object._settings_.enumerable.concat( object._settings_.notEnumerable );
		};
		
		Object.keys = function( object ) {
			return object._settings_.enumerable;
		};
		
		Object.create = function( prototype, descriptors ) {
			var object = new Constructor;
			
			prototype && extend( object, prototype );
			Object.defineProperties( object, descriptors );
			
			return object;
		};
		
		Object.getOwnPropertyDescriptor = function( object, key ) {
			if( !( object instanceof Constructor ) ) return getOwnPropertyDescriptor( object, key ); // if another dom object
			return object._settings_ && object._settings_.descriptors[ key ];
		};
	};
	
	function extend( o1, o2 ) {
		for( var i in o2 ) {
			o1[ i ] = o2[ i ];
		}
	}
	
	if( Object.defineProperty ) {
		Object.each = function( object, callback ) {
			var props = object._settings_ && object._settings_.enumerable;
			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
	}
});

Object.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"

FINoM 03.09.2012 05:09

Чего еще не хватает:
1. Копирования не-перечисляемых свойств прототипа в Object.create (хрен его знает, как это сделать). Для Object.prototype их можно прописать вручную.
2. Удалять дескриптор при удалении свойства (тоже хер знает как).

FINoM 03.09.2012 05:18

И да, хотел потом на основе этой куйни запилить небольшую библиотеку с наследованием конструкторов, но хрен его знает, как наследовать XDomainRequest.

devote 03.09.2012 05:58

FINoM,
мда... много хочешь от ИЕ, радуйся хотя бы этому... Я подкинул небольшую идейку с реквестом, а тестить мне влом, да и времени нет. Пробуй, ищи, авось чего и найдешь))) Будешь первооткрывателем)))

FINoM 03.09.2012 14:38

Цитата:

Сообщение от devote
много хочешь от ИЕ, радуйся хотя бы этому...

Ну блин, элементарное наследование ведь должно работать. А, нет, майкрософт вперде.

Gozar 03.09.2012 15:18

Цитата:

Сообщение от FINoM
нет, майкрософт

:)


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