Вход

Просмотр полной версии : Как переименовать свойство объекта?


Маэстро
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
перезаписываете, удаляете

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

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 (http://javascript.ru/Array/sort)

Маэстро
24.10.2012, 15:24
в основах 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
и? "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
строки, в отличие от объектов - примитивные типы, и вот они как раз-таки копируются заново.

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

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

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

trikadin
24.10.2012, 17:58
можно, конечно, перед присвоением свойств объекту все примитивные типы еще погружать в объекты-оболочки, чтобы такие объекты копировались уже по ссылке...
Если у вас будут храниться многомегабайтные строки (например, картинки) - то это вполне хороший выход.

melky
24.10.2012, 18:02
-Думаю, что да. А Вы?
что мешает перевести примитив в объектное представление?

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

melky
24.10.2012, 18:23
чтобы перевезти доски мы используем грузовик (грузим их в кузов), а чтобы перевезти грузовик, мы используем... опять грузовик! (грузим грузовик в грузовик).
ошибаетесь - мы не грузим их в кузов, а делаем точно такие же доски, загружаем их в кузов, а старые выкидываем.

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

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

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


может, всё-таки поясните, зачем нужен сей велосипед и супер сила?
Ну что тут пояснять, я же вроде написал в начале:
есть 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
Маэстро,
юзайте массивы и будет вам счастье ;)
Ваш совет равносилен например такому: напишите программу на 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/26806-udalenie-ehlementa-v-zhidkom-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
при использовании 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
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
сделать один раз

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
length - длину значений - см. массив.

было бы неплохо не учитывать унаследованные свойства и проверять ключ на принадлежность к числу.
Короче говоря, я тщательно исследовал Ваш код (пример) и пришел к выводу, что со свойством 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