24.10.2012, 22:39
|
Профессор
|
|
Регистрация: 31.05.2012
Сообщений: 396
|
|
Маэстро,
при использовании for (... in ...) порядок перебора свойств в спецификации неопределён, поэтому разные браузеры перебирают их в разном порядке. Если нужно перебрать свойства в определённом порядке, следует использовать другие способы.
Последний раз редактировалось oneguy, 24.10.2012 в 22:43.
|
|
24.10.2012, 22:44
|
Профессор
|
|
Регистрация: 02.07.2010
Сообщений: 642
|
|
У меня тоже мысли крутились вокруг "prototype", но до хэша имен ключей я так и не добрался.
Что касается Вашего примера, то (как я понял) в этом алгоритме надо каким-то образом всегда знать длину length (то ли подсчитывать её при присвоении свойств, то ли запускать общий подсчет позже).
Я считаю, что если вводить сортировку (чтобы привести в разных браузерах к единому виду), то это может потратить приличное время на больших массивах. Поэтому я вообще отказался от неё и в каком порядке идет перебор в "for (var key in m)" меня уже и не интересует.
Вот мой вариант решения:
m = {};
m[7]='7777';
m[6]='6666';
m[5]='5555';
m[1]='1111';
m[17]='1717';
m[2]='2222';
m[25]='2525';
m[3]='3333';
m[8]='8888';
var r = 4; // удаляем свойство №4 и сдвигаем все свойства с номерами более 4 на его место
var tmp = {};
for (var key in m)
{
if (key > r)
tmp[key-1] = m[key];
else tmp[key] = m[key];
};
alert('4=' + m[4] + ' 5=' + m[5] + ' 6=' + m[6] + ' 7=' + m[7]); // 4=undefined 5=5555 6=6666 7=7777
m = tmp;
alert('4=' + m[4] + ' 5=' + m[5] + ' 6=' + m[6] + ' 7=' + m[7]); // 4=5555 5=6666 6=7777 7=8888
|
|
24.10.2012, 22:49
|
Профессор
|
|
Регистрация: 02.07.2010
Сообщений: 642
|
|
Сообщение от oneguy
|
при использовании for (... in ...) порядок перебора свойств в спецификации неопределён
|
Да, спасибо, я знаю это. Вопрос стоял в том, что если Google Chrome и Opera по состоянию на 2012г. делают этот перебор строго по возрастанию числовых ключей объекта, то можно ли на этом уверенно основываться, или нет никаких гарантий, что так будет и в будущем?
Короче, я вообще обошел проблему с сортировкой (см. пример выше)
|
|
24.10.2012, 23:08
|
|
Модератор
|
|
Регистрация: 27.04.2010
Сообщений: 3,417
|
|
Сообщение от Маэстро
|
то можно ли на этом уверенно основываться, или нет никаких гарантий, что так будет и в будущем?
|
Сообщение от Маэстро
|
нет никаких гарантий, что так будет и в будущем
|
Ответ, собственно.
|
|
24.10.2012, 23:15
|
sinistral
|
|
Регистрация: 28.03.2011
Сообщений: 5,418
|
|
Сообщение от Маэстро
|
Что касается Вашего примера, то (как я понял) в этом алгоритме надо каким-то образом всегда знать длину length (то ли подсчитывать её при присвоении свойств, то ли запускать общий подсчет позже).
|
сделать один раз
for (i in obj) length++;
obj.length = length;
после этого добавлять \ уменьшать это значение при добавлении \ удалении элементов - т.е. придётся делать это через серреты и геттеры.
|
|
25.10.2012, 11:45
|
Профессор
|
|
Регистрация: 02.07.2010
Сообщений: 642
|
|
Сообщение от melky
|
Array.prototype.splice.call(myObj, 2, 1);
|
Вообще мне нравятся решения "в одну строку". Я, пожалуй, всё же возьму Ваш вариант. Только у меня пока еще есть смутные сомнения насчет него - надо всячески потестировать при разных вариантах заполнения объекта и удаления его свойств, проверить быстродействие.
Цитата:
|
Если и это не подходит, значит, придётся реализовывать своюь структуру данных, где выборка по ключу будет O(1), и в которой так же можно будет менять ключ.
мне кажется, что это будет трудно
|
А вот посмотрите/прокомментируйте, пожалуйста, примерчик, который я нашел в инете. В частности касательно установки length:
//for (i in obj) length++; obj.length = length; // melky
Array.prototype.associate = function(keys){
var obj = {}, length = Math.min(this.length, keys.length);
for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
return obj;
};
var hash = ['one', 'three', 'two'].associate(['first','3','2']);
var string = '';
for (var i in hash) string += i + ':' + hash[i] + '; ';
alert(string);
// Chrome: 2:two; 3:three; first:one;
// Opera: 2:two; 3:three; first:one;
// FF: first:one; 3:three; 2:two;
// IE: first:one; 3:three; 2:two;
|
|
25.10.2012, 13:48
|
Профессор
|
|
Регистрация: 02.07.2010
Сообщений: 642
|
|
Сообщение от melky
|
сделать один раз
for (i in obj) length++;
obj.length = length;
|
А всё-таки, в Вашем алгоритме свойство length что должно хранить? Потому как for (i in obj) length++; при подсчете количества учтет не только свойства с числовыми индексами, но еще прибавит к счетчику и само свойство length.
Может надо делать obj.length = length - 1; ?
|
|
25.10.2012, 16:46
|
sinistral
|
|
Регистрация: 28.03.2011
Сообщений: 5,418
|
|
Сообщение от Маэстро
|
Вообще мне нравятся решения "в одну строку". Я, пожалуй, всё же возьму Ваш вариант. Только у меня пока еще есть смутные сомнения насчет него - надо всячески потестировать при разных вариантах заполнения объекта и удаления его свойств, проверить быстродействие.
|
вот дока, на всякий.
http://es5.javascript.ru/x15.4.html#x15.4.4.12
вообще, самым быстрым вариантом будет вариант Slavenin, при приведении примитивов в объекты, конечно.
Сообщение от Маэстро
|
А вот посмотрите/прокомментируйте, пожалуйста, примерчик, который я нашел в инете. В частности касательно установки length:
|
он так же не позволяет изменять ключи.
Сообщение от Маэстро
|
А всё-таки, в Вашем алгоритме свойство length что должно хранить?
|
длину значений - см. массив.
Сообщение от Маэстро
|
при подсчете количества учтет не только свойства с числовыми индексами, но еще прибавит к счетчику и само свойство length.
|
конечно. код слишком упрощён, чтобы его использовать в голом виде
было бы неплохо не учитывать унаследованные свойства и проверять ключ на принадлежность к числу.
var length = 0, i;
for (i in obj) if (obj.hasOwnProperty(i) && isFinite(i)) {
length += 1;
}
obj.length = length;
|
|
25.10.2012, 17:02
|
Профессор
|
|
Регистрация: 02.07.2010
Сообщений: 642
|
|
Сообщение от melky
|
length - длину значений - см. массив.
|
Сообщение от melky
|
было бы неплохо не учитывать унаследованные свойства и проверять ключ на принадлежность к числу.
|
Короче говоря, я тщательно исследовал Ваш код (пример) и пришел к выводу, что со свойством length надо быть осторожным.
Не знаю, что Вы подразумевали под "длиной значений", но для нормальной работы Вашего алгоритма в length должно быть не количество элементов (свойств объекта), а максимальный индекс свойства (это максимальное значение ключа), увеличенный на 1. Причем IE как всегда выпендрился: ему не надо к length прибавлять 1, иначе в объекте остается одно лишнее свойство (последнее). Код получился такой:
var myObj = {};
myObj.length = 0; // это не количество элементов, а максимальный индекс + 1
myObj[1]= "1";
myObj[3]= "3";
myObj[2]= "2";
myObj[0]= "0";
myObj[100]= "100";
myObj[99]= "99";
var length = 0;
// подсчет length как количества свойств
///for (i in myObj) length++;
// подсчет length как максимального индекса
for (i in myObj)
{
if (i > length) length = Number(i);
};
if (window.IE)
myObj.length = length;
else myObj.length = length + 1;
var s = '';
for (var key in myObj) s = s + ' ' + key + '=' + myObj[key];
alert('1). ' + s);
// 1). 0=0 1=1 2=2 3=3 99=99 100=100 length=101
Array.prototype.splice.call(myObj, 2, 1); // удаляем один элемент
var s = '';
for (var key in myObj) s = s + ' ' + key + '=' + myObj[key];
alert('2). ' + s);
// 2). 0=0 1=1 2=3 98=99 99=100 length=100
|
|
|
|