2011-01-10 6 views
160

Есть ли умный (то есть оптимизированный) способ переименования ключа в javascript-объекте?JavaScript: Object Переименовать ключ

Не-оптимизированный способ будет:

o[ new_key ] = o[ old_key ]; 
delete o[ old_key ]; 
+11

Что вы имеете в виду под "оптимизированы"? Я не думаю, что это может быть более кратким, чем это; нет «переименования» встроенной операции. – Pointy

+7

Это все, что вы можете получить. Я бы позаботился о других вещах в моем заявлении. И кстати, вы имеете дело с объектами, а не с массивами. В JavaScript нет ассоциативных массивов (в строгом смысле). –

+0

Оптимизированный будет либо более быстрым, либо компактным, либо более читаемым. –

ответ

80

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

Object.prototype.renameProperty = function (oldName, newName) { 
    // Do nothing if the names are the same 
    if (oldName == newName) { 
     return this; 
    } 
    // Check for the old property name to avoid a ReferenceError in strict mode. 
    if (this.hasOwnProperty(oldName)) { 
     this[newName] = this[oldName]; 
     delete this[oldName]; 
    } 
    return this; 
}; 

ECMAScript 5 Удельное

Я хочу синтаксис не был этот комплекс, но это, безусловно, приятно иметь больше контроля.

Object.defineProperty(
    Object.prototype, 
    'renameProperty', 
    { 
     writable : false, // Cannot alter this property 
     enumerable : false, // Will not show up in a for-in loop. 
     configurable : false, // Cannot be deleted via the delete operator 
     value : function (oldName, newName) { 
      // Do nothing if the names are the same 
      if (oldName == newName) { 
       return this; 
      } 
      // Check for the old property name to 
      // avoid a ReferenceError in strict mode. 
      if (this.hasOwnProperty(oldName)) { 
       this[newName] = this[oldName]; 
       delete this[oldName]; 
      } 
      return this; 
     } 
    } 
); 
+4

@ChaosPandion извините, но я действительно устал от ошибки JS-кода , Я в настоящее время пишу Руководство (https://github.com/BonsaiDen/JavaScript-Garden) обо всех причудах (включая тот, который вы сейчас исправили), это могло бы привести меня в какой-то режим тиража;) (Удалено -1 сейчас) –

+1

@Ivo - Не могли бы вы объяснить, почему вы чувствуете, что продление прототипа плохое? Прототипы были сделаны для продления ребенка! – ChaosPandion

+0

@ChaosPandion Не ** ** туземцы **, потому что они вводят весь беспорядок с 'in' и т. Д. Prototype.js - отличный пример ** почему ** это плохо, даже его разработчики признали, что это было плохо чтобы использовать его для библиотеки. –

2

Я бы сказал, что было бы лучше, с концептуальной точки зрения, чтобы просто оставить старый объект (один из веб-службы), как это, и поместить необходимые значения в новом объекте. Я предполагаю, что вы извлекаете определенные поля в какой-то момент или в любом случае, если не на клиенте, то, по крайней мере, на сервере. Тот факт, что вы выбрали имена полей, которые являются теми же, что и в веб-службе, только в нижнем регистре, на самом деле не изменяет это. Таким образом, я бы посоветовал сделать что-то вроде этого:

var myObj = { 
    field1: theirObj.FIELD1, 
    field2: theirObj.FIELD2, 
    (etc) 
} 

Конечно, я делаю все виды предположений здесь, которые не могут быть истинными. Если это не относится к вам, или если оно слишком медленное (не так ли? Я не тестировал, но, я думаю, разница становится меньше по мере увеличения количества полей), пожалуйста, игнорируйте все это:

Если вы не хотите этого делать, и вам нужно только поддерживать определенные браузеры, вы также можете использовать новые геттеры, чтобы также вернуть «uppercase (field)»: см. http://robertnyman.com/2009/05/28/getters-and-setters-with-javascript-code-samples-and-demos/ и ссылки на этой странице для получения дополнительной информации.

EDIT:

Невероятно, но это также почти в два раза быстрее, по крайней мере, на моей FF3.5 на работе. См: http://jsperf.com/spiny001

+0

Большое спасибо за ваши усилия, но прецедент не управляет статическими объектами, так как их структура и глубина не показаны. Поэтому, если возможно, я хотел бы придерживаться первоначальной сферы вопроса. –

109

Наиболее полно (и правильно) способ сделать это было бы, я считаю:

if (old_key !== new_key) { 
    Object.defineProperty(o, new_key, 
     Object.getOwnPropertyDescriptor(o, old_key)); 
    delete o[old_key]; 
} 

Этот метод гарантирует, что переименовано свойство ведет себя идентично исходному.

Кроме того, мне кажется, что возможность обернуть это в функцию/метод и поместить его в Object.prototype, не имеет отношения к вашему вопросу.

+0

Это приятное решение только с ES5 с реальным плюсом сохранения всех свойств. Таким образом, это не «оптимизировано», а определенно более точно на ES5. –

+3

поддержал некоторый скептицизм по отношению к writing_things_with_underscores, но, конечно, это было связано с тем, что человек задал вопрос. это правильный ответ на мой взгляд. –

+3

Хотел бы я дать вам +50000 –

4

Я хотел бы сделать что-то вроде этого:

function renameKeys(dict, keyMap) { 
    return _.reduce(dict, function(newDict, val, oldKey) { 
    var newKey = keyMap[oldKey] || oldKey 
    newDict[newKey] = val 
    return newDict 
    }, {}) 
} 
+3

Сделал обновленную версию вашего решения, которое не преобразует статические ключи в «undefined» здесь: https://gist.github.com/diasdavid/f8997fb0bdf4dc1c3543 Тем не менее, проблема по-прежнему не связана с необходимостью переназначить ключи на нескольких уровнях объекта JSON (переназначая вложенные ключи), идеи? –

3

Лично, самые эффективный способ переименования ключей в объекте без реализации сверхтяжелых плагин и колеса:

var str = JSON.stringify(object); 
str = str.replace(/oldKey/g, 'newKey'); 
str = str.replace(/oldKey2/g, 'newKey2'); 

object = JSON.parse(str); 

Вы также можете обернуть его в try-catch, если ваш объект имеет недопустимую структуру.Работает отлично :)

+11

ooops! var object = {b: '123', 'c': 'bbb'}; var str = JSON.stringify (объект); str = str.replace (/ b/g, 'newKey'); str = str.replace (/ c/g, 'newKey2'); объект = JSON.parse (str); – BlondinkaBrain

+3

Как это сравнить для скорости? – mix3d

+15

Также возникает потенциальная проблема где-то в datavalues ​​- это та же строка, что и имя старого ключа. – mix3d

0

Хотя это не дает лучшего решения для переименования ключа, оно обеспечивает быстрый и простой способ ES6 переименовать все ключи в объекте, не изменяя данные, которые они содержат.

let b = {a: ["1"], b:["2"]}; 
Object.keys(b).map(id => { 
    b[`root_${id}`] = [...b[id]]; 
    delete b[id]; 
}); 
console.log(b); 
+2

Заботьтесь о том, что вы сделали и почему? – empiric

+3

Пожалуйста, используйте ссылку [edit], чтобы объяснить, как работает этот код, и не просто указывать код, так как объяснение, скорее всего, поможет будущим читателям. См. Также [ответ]. [источник] (http://stackoverflow.com/users/5244995) –

+0

Согласен. Он не отвечает на вопрос конкретно, но он помог мне в выполнении работы в качестве решения для переименования всех ключей в объекте. Возможно, я пропустил эту тему. –

12

В случае кто-то должен переименовать список свойств:

function renameKeys(obj, newKeys) { 
    const keyValues = Object.keys(obj).map(key => { 
    const newKey = newKeys[key] || key; 
    return { [newKey]: obj[key] }; 
    }); 
    return Object.assign({}, ...keyValues); 
} 

Использование:

const obj = { a: "1", b: "2" }; 
const newKeys = { a: "A", c: "C" }; 
const renamedObj = renameKeys(obj, newKeys); 
console.log(renamedObj); 
// {A:"1", b:"2"} 
+0

это должно быть принято, отлично работал для моего использования. Мне пришлось преобразовать ответ API, который префиксные имена стран с ненужной строкой. Повернул объект в массив ключей и сопоставил каждую клавишу с помощью метода подстроки и вернул новый объект с новым ключом и значением, индексированным по первому ключу. –

5

Я хотел бы только с помощью ES6(ES2015) путь!

Нам нужно идти в ногу со временем!

const old_obj = { 
 
    k1: `111`, 
 
    k2: `222`, 
 
    k3: `333` 
 
}; 
 
console.log(`old_obj =\n`, old_obj); 
 
// {k1: "111", k2: "222", k3: "333"} 
 

 

 
/** 
 
* @description ES6 ...spread & Destructuring Assignment 
 
*/ 
 

 
const {k1: kA, k2: kB, k3: kC,} = {...old_obj} 
 
console.log(`kA = ${kA},`, `kB = ${kB},`, `kC = ${kC}\n`); 
 
// kA = 111, kB = 222, kC = 333 
 

 
const new_obj = Object.assign(
 
    {}, 
 
    { 
 
     kA, 
 
     kB, 
 
     kC 
 
    } 
 
); 
 
console.log(`new_obj =\n`, new_obj); 
 
// {kA: "111", kB: "222", kC: "333"}

demo screen shortcut

+0

. Нашел это как более чистое решение, если вы хотите превратить искаженный объект в новую реструктурированную. – Daenarys

+0

Хорошо, но я думаю, что const {k1: kA, k2: kB, k3: kC,} = old_obj достаточно? не нужно распространять (если вы не хотите, чтобы копия old_obj). – Hans

Смежные вопросы