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

Маэстро 24.10.2012 11:42

Как переименовать свойство объекта?
 
// создаем объект
var m={};

// создаем у него три свойства и присваиваем им значения
m[5]='mama';
m[6]='papa';
m[7]='deda';

// или так:
m.x='mama';
m.y='papa';
m.z='deda';

alert(m[4] + ' ' + m[5] + ' ' + m[6] + ' ' + m[7]);  // undefined mama papa deda    

// как переименовать свойство "5" в свойство "4", чтобы при обращении к m[4] мы бы получили значение из бывшего m[5], а m[5] типа исчезло вообще?
// имеется ввиду не копирование m[4]=m[5];

Slavenin 24.10.2012 13:13

перезаписываете, удаляете

m = {};
m.a = 'a';
m.b = 'b';
m.c = 'c';

m.b = m.a;
delete m.a;
console.log(m);

Маэстро 24.10.2012 13:44

Цитата:

Сообщение от Slavenin (Сообщение 211949)
перезаписываете, удаляете

Это я уже пробовал. Поэтому специально попросил вариант решения без присвоения одного свойства другому. Почему? -тому есть две причины.

1. В примере я упрощенно написал
m[5]='mama';
m[6]='papa';
m[7]='deda';
Но вместо 'mama' и 'papa' в данных свойствах могут храниться другие многомегабайтные объекты. Присвоение одного свойства другому приведет (я так интуитивно считаю) к перегону больших массивов информации по памяти из одного места в другое. А если в объекте m несколько тысяч свойств, то процедура будет работать долго.

2. Показанный мною пример - это упрощенный случай задачи (тоже несколько упрощаю формулировку):
Есть объект m={}; причем подчеркиваю, что это не массив m=[];
Данный объект содержит тысячу свойств m[1]...m[1000].
Необходимо удалить 100-е свойство из данного объекта, и все свойства, что имеют ключ > 100 сместить "вниз", в сторону меньших индексов. То есть 101-е свойство должно стать сотым, 102-е перейти на 101-е,... 1000-е перейти на 999-е.
На ум приходит организовать цикл - перебор свойств и "перенос" данных из одного свойства в другое:
for (var key in m)  m[key-1] = m[key];
Это работает! Однако, как всегда кто-нибудь это обезобразит! Проверка в разных браузерах показала, что
-перебор от млаших к старшим key идет только в Opera и Google Chrome.
-в Fire Fox перебор идет в том же порядке, в котором шло присвоение свойств
-в IE также как и в Fire Fox перебор идет в том же порядке, в котором шло присвоение свойств, однако после прохода последнего элемента, созданного до цикла начинается просмотр элементов, созданных в цикле (что приводит к зависанию...)
т.е. если присвоение было не последовательно в порядке возрастания ключей
m[7]='deda';
m[6]='papa';
m[5]='mama';
m[1]='1111';
m[17]='1717';
m[2]='2222';
m[25]='2525';
m[3]='3333';

то Fire Fox и IE дадут кашеобразный результат.

melky 24.10.2012 14:05

Цитата:

Сообщение от Маэстро
многомегабайтные объекты. Присвоение одного свойства другому приведет (я так интуитивно считаю) к перегону больших массивов информации по памяти из одного места в другое.

в основах JS говорится, что объекты передаются не по значению, а по ссылке.

т.е. многомегабайтовый объект останется валяться там, где валялся.

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

Slavenin 24.10.2012 14:23

Цитата:

то Fire Fox и IE дадут кашеобразный результат.
и? sort

Маэстро 24.10.2012 15:24

Цитата:

Сообщение от melky (Сообщение 211959)
в основах JS говорится, что объекты передаются не по значению, а по ссылке.
т.е. многомегабайтовый объект останется валяться там, где валялся.

Да, говорится. Но не факт. Что означает по ссылке? Это означает, что если после "передачи объекта" изменить второй объект, то изменения незамедлительно отразятся в первом объекте. Это значит, что и первый, и второй объект ссылаются на одну и ту же зону памяти, которая "валяется там, где валяется". Так с объектами. Однако не со свойствами объектов (при их копировании одного другому). Сравните:
var m1 = {};
var m2 = {};
var m3 = {};
      
m1[5]='mama';
m2=m1; // присвоение по ссылке
m3[5] = m1[5]; // присвоение не по ссылке (копирование/дублирование данных)
m1[5] = 'privet'; // изменим объект m1 - повлияет ли он на m2 и m3? 
      
alert('m1[5]=' + m1[5] + ' m2[5]=' + m2[5] + ' m3[5]=' + m3[5]);
// выведет: m1[5]=privet m2[5]=privet m3[5]=mama

Маэстро 24.10.2012 15:26

Цитата:

Сообщение от Slavenin (Сообщение 211961)
и? "http://javascript.ru/Array/sort"

1. sort работает только с массивами m=[];
2. у меня объект m={};

trikadin 24.10.2012 16:37

Цитата:

Сообщение от Маэстро
Да, говорится. Но не факт.

Охренеть. Почему не факт??? Это написано в документации, и браузеры работают только так. А ваш пример просто идиотский - строки, в отличие от объектов - примитивные типы, и вот они как раз-таки копируются заново.

Учим матчасть, короче.

trikadin 24.10.2012 16:42

Допишу примерчик ещё:

var m1 = {};
var m2 = {};
var m3 = {};
       
m1[5]={"bla": 123};
m2=m1; 
m3[5] = m1[5]; 
m1["5"].bla = 12345

alert(m1[5].bla +" "+ m2[5].bla + " " + m3[5].bla)

Dim@ 24.10.2012 16:51

Маэстро,
мдаа залёт конечно такой бред нести, ну ладно:
Цитата:

Сообщение от Маэстро
Что означает по ссылке? Это означает, что если после "передачи объекта" изменить второй объект, то изменения незамедлительно отразятся в первом объекте. Это значит, что и первый, и второй объект ссылаются на одну и ту же зону памяти, которая "валяется там, где валяется". Так с объектами. Однако не со свойствами объектов (при их копировании одного другому)

1
Цитата:

Однако не со свойствами объектов (при их копировании одного другому)
это не так
2
Цитата:

Это означает, что если после "передачи объекта" изменить второй объект, то изменения незамедлительно отразятся в первом объекте.
естественно так как они ссылаются на одно и тоже
3
Цитата:

Так с объектами
и с массивами тоже как я помню, и абсолютно неважно является ли они свойствами других объектов

Маэстро 24.10.2012 17:17

Цитата:

Сообщение от trikadin (Сообщение 211989)
строки, в отличие от объектов - примитивные типы, и вот они как раз-таки копируются заново.

Хорошо, напишу, где я допустил неточность. В фразе "Но вместо 'mama' и 'papa' в данных свойствах могут храниться другие многомегабайтные объекты." имелось ввиду не JS-объекты, а "информационные объекты", коими могут быть и js-строки. Я НЕ знаю заранее, что там может быть. А если там будут строки длиной 2 гигабайта? Они будут копироваться заново?
-Думаю, что да. А Вы?

P.S. можно, конечно, перед присвоением свойств объекту все примитивные типы еще погружать в объекты-оболочки, чтобы такие объекты копировались уже по ссылке... но не масло ли масляное?

Маэстро 24.10.2012 17:23

Цитата:

Сообщение от Dim@
мдаа залёт конечно такой бред нести, ну ладно:

Что за дурацкая привычка сразу свистеть? бред... залет... Вы на первом году службы в армии, или в цирке? Зачем цепляться к одному слову? По существу топика можете что-то сказать?
Я написал о двух проблемах в топике. Первую обсудили (будем так считать ). А что делать со второй?
У меня есть своё решение с помощью создания второй копии массива m2={}, но оно мне не нравится по потреблению ресурсов (в какое-то время будет существовать две копии боольших массивов), поэтому хотелось бы услышать мнение профессионалов по более изящному варианту решения.

trikadin 24.10.2012 17:58

Цитата:

Сообщение от Маэстро
можно, конечно, перед присвоением свойств объекту все примитивные типы еще погружать в объекты-оболочки, чтобы такие объекты копировались уже по ссылке...

Если у вас будут храниться многомегабайтные строки (например, картинки) - то это вполне хороший выход.

melky 24.10.2012 18:02

Цитата:

Сообщение от Маэстро
-Думаю, что да. А Вы?

что мешает перевести примитив в объектное представление?

Маэстро 24.10.2012 18:10

Цитата:

Сообщение от melky (Сообщение 212010)
что мешает перевести примитив в объектное представление?

Категорически ничего не мешает. Просто чтобы перевезти доски мы используем грузовик (грузим их в кузов), а чтобы перевезти грузовик, мы используем... опять грузовик! (грузим грузовик в грузовик).
Ну да черт с ним. А по вопросу сортировки свойств в объекте можете что-то подсказать?
Хотя, идеально было бы делать то, что я назвал "переименованием" свойств объекта. Знаю, что все имена (названия свойств) - это хэш-массив. Как туда добраться? Есть способ?

melky 24.10.2012 18:23

Цитата:

Сообщение от Маэстро
чтобы перевезти доски мы используем грузовик (грузим их в кузов), а чтобы перевезти грузовик, мы используем... опять грузовик! (грузим грузовик в грузовик).

ошибаетесь - мы не грузим их в кузов, а делаем точно такие же доски, загружаем их в кузов, а старые выкидываем.

может, всё-таки поясните, зачем нужен сей велосипед и супер сила?

Маэстро 24.10.2012 18:40

Цитата:

Сообщение от melky (Сообщение 212020)
ошибаетесь - мы не грузим их в кузов, а делаем точно такие же доски, загружаем их в кузов, а старые выкидываем.

Ну почему же я ошибаюсь? Масло масляное-то ведь не в досках, а в грузовиках, то есть в объектах, которые тоже придется заключать в объекты, т.к. заранее не известно что везём. Следуя Вашей аналогии получается так:
мы не грузим их (грузовики) в кузов, а делаем точно такие же грузовики, загружаем их в кузов, а старые (грузовики) выкидываем.
-во как ;)

Цитата:

может, всё-таки поясните, зачем нужен сей велосипед и супер сила?
Ну что тут пояснять, я же вроде написал в начале:
есть js-объект m, содержащий другие js-объекты (с черти-каким содержимым - там некие структуры и шифрованные данные). Назовем их "контейнеры".
Все свойства объекта m нумеруются (обзываются) натуральными числами от 0 до nn=10000. Этим свойствам присвоены контейнеры.
Требуется удалить любое свойство n при этом все остальные свойства от n+1 до nn должны сдвинуться в сторону меньших номеров.
n+1 должно стать на место n, n+2 должно стать на место n+1 и т.д.

Dim@ 24.10.2012 20:55

Маэстро,
юзайте массивы и будет вам счастье ;)

Маэстро 24.10.2012 21:10

Цитата:

Сообщение от Dim@ (Сообщение 212042)
Маэстро,
юзайте массивы и будет вам счастье ;)

Ваш совет равносилен например такому: напишите программу на Delphi и будет вам счастье!
Я же говорил, что у меня не массив, а объект. И заменить его на массив я не могу. Только не спрашивайте почему - не уводите дискуссию в сторону. А то, что сортировка в разных браузерах хеша ключей разная - это тоже МОЯ проблема? Кстати, сортировку по возрастанию в Хроме даже осуждают! http://habrahabr.ru/qa/3749/
Вот только интересно, кто победит? Те, кто осуждают, или компания Гугл?

melky 24.10.2012 21:47

Заимстоввание методов не пробовали?

var myObj = {

    "0": "0",
    "1": "1",
    "2": "2",
    "3": "3",
    
    "length": 4
};

alert( myObj["2"] ); // 2

Array.prototype.splice.call(myObj, 2, 1);

alert( myObj["2"] ); // 3


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

мне кажется, что это будет трудно, посему желаю вам удачи.


вообще, такая структура данных у правил в CSS таблицах :
http://javascript.ru/forum/misc/2680...kom-liste.html
я с этим сталкивался уже.

в принципе, можно глянуть в исходниках на Java, как они сделали эти списки, и так же сделать на JS - это как вариант.

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, время: 12:04.