Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Как переименовать свойство объекта? (https://javascript.ru/forum/events/32639-kak-pereimenovat-svojjstvo-obekta.html)

oneguy 24.10.2012 22:39

Маэстро,
при использовании for (... in ...) порядок перебора свойств в спецификации неопределён, поэтому разные браузеры перебирают их в разном порядке. Если нужно перебрать свойства в определённом порядке, следует использовать другие способы.

Маэстро 24.10.2012 22:44

У меня тоже мысли крутились вокруг "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

Цитата:

Сообщение от oneguy
при использовании for (... in ...) порядок перебора свойств в спецификации неопределён

Да, спасибо, я знаю это. Вопрос стоял в том, что если Google Chrome и Opera по состоянию на 2012г. делают этот перебор строго по возрастанию числовых ключей объекта, то можно ли на этом уверенно основываться, или нет никаких гарантий, что так будет и в будущем?
Короче, я вообще обошел проблему с сортировкой (см. пример выше)

trikadin 24.10.2012 23:08

Цитата:

Сообщение от Маэстро
то можно ли на этом уверенно основываться, или нет никаких гарантий, что так будет и в будущем?

Цитата:

Сообщение от Маэстро
нет никаких гарантий, что так будет и в будущем

Ответ, собственно.

melky 24.10.2012 23:15

Цитата:

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

сделать один раз
for (i in obj) length++;
obj.length = length;

после этого добавлять \ уменьшать это значение при добавлении \ удалении элементов - т.е. придётся делать это через серреты и геттеры.

Маэстро 25.10.2012 11:45

Цитата:

Сообщение от 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

Цитата:

Сообщение от melky (Сообщение 212070)
сделать один раз
for (i in obj) length++;
obj.length = length;

А всё-таки, в Вашем алгоритме свойство length что должно хранить? Потому как for (i in obj) length++; при подсчете количества учтет не только свойства с числовыми индексами, но еще прибавит к счетчику и само свойство length.
Может надо делать obj.length = length - 1; ?

melky 25.10.2012 16:46

Цитата:

Сообщение от Маэстро
Вообще мне нравятся решения "в одну строку". Я, пожалуй, всё же возьму Ваш вариант. Только у меня пока еще есть смутные сомнения насчет него - надо всячески потестировать при разных вариантах заполнения объекта и удаления его свойств, проверить быстродействие.

вот дока, на всякий.
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

Цитата:

Сообщение от 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


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