Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   FAQ Баги браузеров. (https://javascript.ru/forum/offtopic/33616-faq-bagi-brauzerov.html)

Gozar 10.04.2014 19:03

Цитата:

Сообщение от Octane
я только начинал верить в IE

Ахаха :)

nerv_ 11.04.2014 00:09

Цитата:

Сообщение от Octane
придется фиксить так

Не помню с какого осла, но майкрософт заявила, что не хочет отличатся от остальных браузеров по юзер-агенту. Так что теперь это одна из "фич" новых IE :)

Octane 11.04.2014 00:31

Короче тут обсуждали https://twitter.com/DmitryKorobkin/s...81153034596354
Если фиксить через new NOP, то возникает проблема: Object.create(null) instanceof Object → true, а так быть не должно, поэтому последний вариант:
//IE9-11 Object.create bug fix
(function () {
	var object = Object.create({});
	object[0] = null;
	return object.hasOwnProperty(0); //→ false in IE9-11
}()) || new function () {
	var create = Object.create;
	Object.create = function (prototype, properties) {
		//Object.defineProperties fixes a bug
		if (properties) {
			return create(prototype, properties);
		}
		//If Object.create works via new NOP, then
		//Object.create(null) instanceof Object → true,
		//but it's wrong.
		//https://twitter.com/WebReflection/status/454342010288078848
		if (prototype === null) {
			return create(null, {
				"": {
					configurable: true,
					writable: true
				}
			});
		}
		function NOP() {}
		NOP.prototype = prototype;
		return new NOP;
	};
};
да, теперь для Object.create(null), метод Object.getOwnPropertyNames будет возвращать лишнее пустое свойство, но лучше варианта пока не придумал.

devote 11.04.2014 12:00

А не проще тогда уж поправить hasOwnProperty
//IE9-11 Object.create bug fix
(function () {
    var object = Object.create({});
    object[0] = null;
    return object.hasOwnProperty(0); //> false in IE9-11
}()) || new function () {
    var hasOwnProperty = Object.prototype.hasOwnProperty;
    Object.prototype.hasOwnProperty = function(prop) {
      // если числовое свойство ищем
      return +prop == prop ?
            Object.getOwnPropertyNames(this).indexOf(""+prop) != -1 :
            hasOwnProperty.apply(this, arguments);
    };
};

Octane 11.04.2014 12:19

Тогда и getOwnPropertyDescriptor, и propertyIsEnumerable фиксить придется, может еще что-нибудь

Дзен-трансгуманист 11.04.2014 21:17

Баг интерфейса в FF28, замечен в винде:

Встроенный редактор JS иногда перестает исполнять код. Это бывает неочевидно, например, когда код чисто логический и не подразумевает каких-либо визуальных эффектов. Поэтому сопровождайте его хотя бы console.log, если ниче не логирует - лечится открыванием нового окна редактора.

kobezzza 11.04.2014 23:32

Дзен-трансгуманист, ты не сюда пости, а в баг-трекер мозиллы:)

nerv_ 12.04.2014 00:05

Цитата:

Сообщение от kobezzza
Дзен-трансгуманист, ты не сюда пости, а в баг-трекер мозиллы

Дзен-трансгуманист, не слушай его. Тогда тема будет неактуальна :D

devote 12.04.2014 03:09

Цитата:

Сообщение от Octane
Тогда и getOwnPropertyDescriptor, и propertyIsEnumerable фиксить придется, может еще что-нибудь

Ок, тогда не нужно никаких NOPов, все делается просто:
//IE9-11 Object.create bug fix
(function () {
    var object = Object.create({});
    object[0] = null;
    return object.hasOwnProperty(0); //> false in IE9-11
}()) || new function () {
    var create = Object.create;
    Object.create = function (prototype, properties) {
        var isExecNum = properties && Object.getOwnPropertyNames(properties).indexOf("0") != -1;

        if (!isExecNum) {
            properties = properties || {};
            /**
             * Нужно добавить именно числовое свойство, иначе не будет работать
             * например такой вариант не работает:
             *   var o = Object.create({}, {"": {configurable: true}});
             *   delete o[""];
             *   o[0] = null;
             *   o.hasOwnProperty(0) // -> false
             * но если вместо пустой строки поставить число, то все работает хорошо
             */
            properties["0"] = {
                configurable: true
            };
        }

        var object = create.call(this, prototype, properties);

        if (!isExecNum) {
            delete object["0"];
            delete properties["0"];
        }
        return object;
    };
};

Octane 12.04.2014 10:56

О это хорошо, теперь фикс ничем не помешает. Я думаю, можно не выполнять никаких проверок, кроме наличия properties:
//IE9-11 Object.create bug fix
(function () {
	var object = Object.create({});
	object[0] = null;
	return object.hasOwnProperty(0); //→ false in IE9-11
}()) || new function () {
	var create = Object.create;
	Object.create = function (prototype, properties) {
		var object;
		if (properties) {
			//Object.defineProperties fixes a bug
			object = create(prototype, properties);
		}
		else {
			//numeric key fixes a bug,
			//it can be removed after,
			//unlike alphabetic key
			object = create(prototype, {
				"0": {
					configurable: true
				}
			});
			delete object[0];
		}
		return object;
	};
};

melky 12.04.2014 11:39

Цитата:

Сообщение от Дзен-трансгуманист
Баг интерфейса в FF28, замечен в винде:

я думал, это фича такая :)

devote 12.04.2014 11:41

Octane,
Твой вариант не будет работать если я сделаю так:
var o = Object.create({}, {});
o[0] = null;
o.hasOwnProperty(0); // false

melky 12.04.2014 11:58

Цитата:

Сообщение от devote (Сообщение 307381)
Octane,
Твой вариант не будет работать если я сделаю так:
var o = Object.create({}, {});
o[0] = null;
o.hasOwnProperty(0); // false

сами проставляем configurable для всех свойств дескриптора?

devote 12.04.2014 12:00

melky,
Зачем? Просто для ИЕ нужно проинициализировать объект

Octane 12.04.2014 12:51

Цитата:

Сообщение от devote
Твой вариант не будет работать если я сделаю так:
var o = Object.create({}, {});
o[0] = null;
o.hasOwnProperty(0); // false

да точно :(

defineProperties только enumerable свойства берет из объекта с дескрипторами

devote, твой вариант не работает, если сделать так:
var desc = Object.create({}, {"0": {}});

var obj = Object.create({}, desc);
obj[1] = 1;

console.log(obj.hasOwnProperty(1));
а если вместо getOwnPropertyNames будем использовать keys, можем случайно удалить non-enumerable свойство. Вряд ли конечно кто-то так будет делать, но хочется 100% вариант)

-----------
наверное лучше getOwnPropertyDescriptor использользовать

Octane 12.04.2014 13:32

//IE9-11 Object.create bug fix
//http://webreflection.blogspot.ru/2014/04/all-ie-objects-are-broken.html
(function () {
	var object = Object.create({});
	object[0] = null;
	return object.hasOwnProperty(0); //→ false in IE9-11
}()) || new function () {
	var create = Object.create;
	Object.create = function (prototype, properties) {
		var object = create(prototype, properties);
		if (!Object.hasOwnProperty.call(object, 0)) {
			//numeric key fixes a bug,
			//it can be removed after,
			//unlike alphabetic key
			Object.defineProperty(object, 0, {
				configurable: true
			});
			delete object[0];
		}
		return object;
	};
};

devote 12.04.2014 18:54

Octane,
Да отличное решение. Мои тесты все прошел.

nerv_ 12.04.2014 19:06

Цитата:

Сообщение от devote
Да отличное решение.

Меня от этой записи передергивает
new function () {

:)

А еще есть вопрос: это
alert(Object.hasOwnProperty)

в каком стандарте написано?

devote 12.04.2014 19:10

Цитата:

Сообщение от nerv_
каком стандарте написано?

любой объект имеет это свойство по наследству. Ведь конструктор Object тоже является объектом, потому и имеет это свойство. Хотя конечно не спорю, привычнее видеть:
Object.prototype.hasOwnProperty


Да и это тоже смущает:
var object = create(prototype, properties);
Как то все же лучше делать/видеть так:
var object = create.call(this, prototype, properties);
Потому как не сделав этого, мы лишаем прога передать иной контекст. Хотя конечно в данном случае он мало чем поможет.

monolithed 12.04.2014 19:11

Цитата:

Сообщение от nerv_
Меня от этой записи передергивает
new function () {

void function () {
   return {
       // ...
   };
}();

Считаешь, что эта лучшей? ;)

nerv_ 12.04.2014 19:16

Цитата:

Сообщение от devote
любой объект имеет это свойство по наследству. Ведь конструктор Object тоже является объектом, потому и имеет это свойство. Хотя конечно не спорю, привычнее видеть:
Object.prototype.hasOwnProperty

спасибо
Object.prototype.test = 1;
      
alert(Object.test);

nerv_ 12.04.2014 19:29

Цитата:

Сообщение от monolithed
Считаешь, что эта лучшей?

ну, например, как-то так
//IE9-11 Object.create bug fix
//http://webreflection.blogspot.ru/2014/04/all-ie-objects-are-broken.html
(function() {
    var polyfill = {
        isRequired: function() {
            var object = Object.create({});
            object[0] = null;
            return !object.hasOwnProperty(0); //→ false in IE9-11
        },
        apply: function() {
            var create = Object.create;
            Object.create = function(prototype, properties) {
                var object = create(prototype, properties);
                if(!Object.hasOwnProperty.call(object, 0)) {
                    //numeric key fixes a bug,
                    //it can be removed after,
                    //unlike alphabetic key
                    Object.defineProperty(object, 0, {
                        configurable: true
                    });
                    delete object[0];
                }
                return object;
            };
        }
    };

    if(polyfill.isRequired()) {
        polyfill.apply();
    }
}());

С английским мог ошибиться, но суть должна быть ясна :)

Octane 12.04.2014 19:30

Цитата:

Сообщение от devote
Как то все же лучше делать/видеть так:
var object = create.call(this, prototype, properties);

Потому как не сделав этого, мы лишаем прога передать иной контекст.

Ни один дженерик не привязан к контексту, делать call бессмысленно.


Цитата:

Сообщение от nerv_
Меня от этой записи передергивает
new function () {

это чтобы от скобочек в глазах не рябило :D


Цитата:

Сообщение от nerv_
ну, например, как-то так

не ну так конечно красивее, но в твоем варианте все браузеры создадут объект, у меня просто паранойя по этому поводу :)

monolithed 12.04.2014 19:37

nerv_,

Object.prototype[0] = 1;
alert([][0]);

nerv_ 12.04.2014 19:49

Цитата:

Сообщение от monolithed (Сообщение 307432)
nerv_,

Object.prototype[0] = 1;
alert([][0]);

здесь ясно
Object.prototype[0] = 1;
alert([][0]);
alert(''[0]);
alert(0[0]);

Цитата:

Сообщение от Octane
не ну так конечно красивее, но в твоем варианте все браузеры создадут объект, у меня просто паранойя по этому поводу

Т.е. запускать функцию как конструктор (использовать НЕ по назначению) - это нормально? :) Вопрос риторический.
Дело не в "красивей". Понятней (как мне кажется).
А объект, как создаться, так и уничтожится, если он не нужен.

Впрочем, это лишь мое мнение :)

monolithed 12.04.2014 20:11

Цитата:

Сообщение от nerv_
Т.е. запускать функцию как конструктор (использовать НЕ по назначению) - это нормально?

Это просто инстанс объекта, т.е. идентично:
var foo = function () {};
new foo;

Что тут ненормального?

Octane 12.04.2014 20:15

Из вариантов создания локального контекста по условию
namespace.property || new function () {
	…
};

//или

if (!namespace.property) {
	(function () {
		…
	}());
}

//или

(function () {
	if (!namespace.property) {
		…
	}
}());

//или

(function () {
	if (!namespace.property) {
		return false;
	}
	…
	return true;
}());
я выбрал для себя первый

а это
(function () { /*test case*/ }()) || new function () {
	…
};
уже уже вытекающее

я бы конечно написал бы
new function () { /*test case*/ } || new function () {
	…
};
но примитивное значение из конструктора вернуть нельзя, для него автоматически выполнится Object(value), которое будет всегда true

monolithed 12.04.2014 20:34

Цитата:

Сообщение от Octane
но примитивное значение из конструктора вернуть нельзя, для него автоматически выполнится Object(value), которое будет всегда true

Если сильно хочется, то можно так сделать:

alert(+new function () {
   this.valueOf = function () {
      return 1;
   };
});

:)

Цитата:

Сообщение от Octane
Из вариантов создания локального контекста по условию

Можно еще добавить:

namespace.property || void function () {
     ...
}();

Octane 12.04.2014 22:43

Кстати, что-то не понял, думал let уже есть во всех браузерах, но почему-то Aurora 30 ошибку выдает. Вроде в Firefox это первым появлялось.
Ждал, что догадаются сделать, чтобы работало так:
let label: {
    //local scope
}
и чтобы метка была опциональной, а вся конструкция работала в выражении
window.Anything || let {
	…
}
но мечты не сбываются.

monolithed 12.04.2014 23:22

И не говори...

var array = [];

for (let i = 0; i < 2; i++) array.push(() => i);

array[0](); // 0 - Traceur, 2 - FF
array[1](); // 1 - Traceur, 2 - FF


Еще и скобочки лишние () писать нужно :(

Octane 14.04.2014 01:25

Не долго я радовался простому способу создания Array generic methods, баг Array.splice в IE8:
var obj = {
	"0": "a",
	"1": "b",
	"2": "c",
	length: 3
};

[].splice.call(obj, 1, 1);

alert(JSON.stringify(obj)); //→ {"0":"a","1":"c","2":"c","length":2}
           //остальные браузеры {"0":"a","1":"c","length":2}

Большинство результатов в Google с жалобой на то, что 2-й аргумент в IE обязательный, но этот баг тоже нагуглился http://stackoverflow.com/questions/1...ss-browser-ie8

monolithed 14.04.2014 11:05

var holder = { 
    i: 0, 
    toString: function() {
        return this.i++;
    } 
}; 

var object = {}; 
object[holder] = holder + ''; 
object[holder] = holder + ''; 

object; // ?

devote 14.04.2014 11:56

Цитата:

Сообщение от Octane
Array generic methods, баг Array.splice в IE8:

Старый баг, я на него наткнулся еще когда селекторы писал, решается так:
(function(o){
    Array.prototype.splice.call(o, 1, 1);
    return o[1] !== 1;
}({"0": 0, "1": 1, "length": 2})) || new function() {
    var splice = Array.prototype.splice;
    Array.prototype.splice = function(offset, count) {
        var result = splice.apply(this, arguments);
        if (!(this instanceof Array)) {
            while(count--) {
                delete this[this.length + count];
            }
        }
        return result;
    }
};
 
[].splice.call(obj, 1, 1);
 
alert(JSON.stringify(obj)); // {"0":"a","1":"c","length":2}

Octane 14.04.2014 14:06

Цитата:

Сообщение от devote
Старый баг, я на него наткнулся еще когда селекторы писал, решается так:

Обычно push.call и slice.call хватало, до splice как то дело не доходило) Да и сейчас наткнулся, потому что от нечего делать метод array.remove писал.

Цитата:

Сообщение от monolithed
var holder = { 
    i: 0, 
    toString: function() {
        return this.i++;
    } 
}; 

var object = {}; 
object[holder] = holder + ''; 
object[holder] = holder + ''; 

object; // ?

{"0":"1","2":"3"} //IE8
{"1":"0","3":"2"} //другие браузеры

Я так понял в IE8 сначала создается object[holder] = undefined, а потом выполняется присваивание вычисленного значения

Aetae 14.04.2014 14:32

Вообще по общей логике javascript(исполнение слева-направо) IE тут прав, ибо по сути то:
var holder = {
    i: 0,
    toString: function() {
        return this.i++;
    }
}
var object = {};
object[holder.toString()] = holder.toString() + '';
object[holder.toString()] = holder.toString() + '';
 
alert(JSON.stringify(object));

devote 14.04.2014 14:54

Не знаю к чему вы это, но я тоже внесу свою лепту ;)
new function() {
    var i = 0;
    Object.defineProperty(window, 'holder', {
        configurable: true,
        get: function() {
            return i++;
        }
    });
}

var object = {};
object[holder] = holder;
object[holder] = holder;
 
alert(JSON.stringify(object));

Aetae 14.04.2014 15:16

devote, к тому что toString ведёт себя не как гетер, а как хз что.
Интересно спеки говорят что нибудь об этом?..

devote 14.04.2014 15:31

Цитата:

Сообщение от Aetae
к тому что toString ведёт себя не как гетер, а как хз что.

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

Понятно дело что в этом случае браузеру нужно гадать, конвертить или нет:
object[holder]
вот так он поймет конечно что нужно вызвать toString, так как явно указывает на это:
object[holder + '']

Aetae 14.04.2014 15:37

devote, не, понятно конечно что ситуация неопределённая, но holder то объект, так что конвертить полюбасу придётся. Я лично в данной ситуации на стороне ie.

monolithed 14.04.2014 15:38

Цитата:

Сообщение от devote
object[holder + '']

Ага, хоть кто-то на это обратил внимание :victory:


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