자바 스크립트 : Object Rename Key


299

자바 스크립트 객체에서 키의 이름을 바꾸는 영리한 (즉 최적화 된) 방법이 있습니까?

최적화되지 않은 방법은 다음과 같습니다.

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

14
"최적화"란 무엇을 의미합니까? 나는 그것이 그것보다 더 간결 해 질 수 있다고 생각하지 않는다. "이름 바꾸기"내장 조작이 없습니다.
Pointy

9
그것이 당신이 얻을 수있는 전부입니다. 내 응용 프로그램의 다른 것들에 대해 걱정할 것입니다. 그리고 btw, 당신은 배열이 아닌 객체를 다루고 있습니다. JavaScript에는 연관 배열이 없습니다 (엄격한 의미로).
Felix Kling

3
@Jean Vincent : 느려요?
Felix Kling

8
이것은 가장 최적화 된 기본 버전입니다
Livingston Samuel

4
귀하의 버전은 Safari, 샘플 테스트 사례 @ jsperf.com/livi-006을
Livingston Samuel

답변:


193

가장 완벽하고 정확한 방법은 다음과 같습니다.

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

이 방법을 사용하면 이름이 바뀐 속성 원래 속성 과 동일하게 동작합니다 .

또한, 이것을 함수 / 메소드로 감싸서 넣을 가능성 Object.prototype은 귀하의 질문과 관련이없는 것 같습니다.


1
이것은 모든 속성을 실제로 보존하는 훌륭한 ES5 전용 솔루션입니다. 따라서 이것은 "최적화"된 것이 아니라 ES5에서 더 정확합니다.
Jean Vincent

6
writing_things_with_underscores에 대한 회의론에 찬성했지만 물론 그것은 질문하는 사람 때문이었습니다. 이것은 내 견해로는 올바른 대답입니다.
벤트 카르 단

3
중요한 경우, ES5의 이러한 특정 사용법은 IE9 및 최신 솔루션이라고 생각합니다.
Scott Stafford

1
o.old_key가 존재하는지 확인하는 것이 좋습니다. 변경 : : if (old_key !== new_key): if (old_key !== new_key && o[old_key])
jose

100

작품을 함수로 감싸서 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 코드에 정말 지쳤습니다. 현재 모든 문제 (현재 수정 한 것을 포함하여)에 대한 안내서 ( github.com/BonsaiDen/JavaScript-Garden )를 작성하고 있습니다. 이것은 나를 일종의 rant 모드로 만들었을 것입니다;) (지금 -1을 제거했습니다)
Ivo Wetzel

1
@Ivo-프로토 타입 확장이 나쁘다고 느끼는 이유를 설명해 주시겠습니까? 아기를 연장하기 위해 프로토 타입이 만들어졌습니다!
ChaosPandion

5
@Ivo-위험하다는 데 동의하지만 프로토 타입이 더 표현적인 코드로 이어 졌다고 생각되면 프로토 타입을 확장하지 못하게 할 요소는 없습니다. ECMAScript 5 사고 방식에서 왔지만을 통해 속성을 열거 불가능으로 표시 할 수 있습니다 Object.defineProperty.
ChaosPandion

3
@Ivo- hasOwnProperty속성을 확인하고 for ... in루프 내 에서 항상 확인 하는 것이 적절한 경우 Object를 확장하면 왜 중요한가요?
David Tang

2
이 코드는 작동하지만 새 키 이름이 이미 존재하면 그 값이 줄어든다
Brandon Minton

83

소스 객체를 변경하는 경우 ES6에서 한 줄로 수행 할 수 있습니다.

delete Object.assign(o, {[newKey]: o[oldKey] })[oldKey];

또는 새 객체를 만들려는 경우 두 줄입니다.

const newObject = {};
delete Object.assign(newObject, o, {[newKey]: o[oldKey] })[oldKey];

5
시도 : delete Object.assign (o, {newKey : o.oldKey}). oldKey; 나를 위해 잘 일했다
Tim

2
왜 대괄호가 []주위에 newKey있습니까? 실제로 솔루션은 작동하지 않습니다.
Soumya Kanti

2
좋아-나는 대답을 얻었다. ES6 기능입니다. 나와 같은 다른 사람이 우연히 발견되면 여기에 좋은 대답이 있습니다.
Soumya Kanti

1
변수 이름이 더 장황하면이 대답이 더 강력합니다.
lowcrawler

1
혹시? 죄송합니다. 처음 의견으로 생각한 것을 잊었습니다.
lowcrawler

42

누군가 속성 목록의 이름을 바꿔야 할 경우 :

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"}

2
이것은 대답이어야하며 내 유스 케이스에 효과적이었습니다. 국가 이름 앞에 불필요한 문자열이있는 API 응답을 변환해야했습니다. Object를 키 배열로 바꾸고 하위 문자열 메서드를 사용하여 각 키를 통해 매핑하고 원래 키로 인덱스 된 새 키와 값을 가진 새 객체를 반환
Akin Hwan

1
이전 키를 삭제하지 않기 때문에 좋습니다. 이전 키를 삭제하면 키 이름이 변경되지 않은 경우 객체에서 키가 완전히 제거됩니다. 내 예제에서는 변환 된 my_object_property위해 myObjectProperty내 재산을 단일하게 표현 인 경우, 그러나, 다음 키가 제거되었습니다. +1
blueprintchris

25

그냥 ES6(ES2015)길을 사용하고 싶습니다 !

우리는 시대를 따라야합니다!

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


/**
 * @author xgqfrms
 * @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"}

데모 화면 바로 가기


1
조작 된 오브젝트를 새로운 재구성 된 오브젝트로 변환하려는 경우이 솔루션을보다 깨끗한 솔루션으로 찾았습니다.
NJInamdar

5
좋은 것이지만 const {k1 : kA, k2 : kB, k3 : kC,} = old_obj가 충분하다고 생각합니다. 확산 할 필요가 없습니다 (old_obj의 사본을 원하지 않는 한).
한스

@ 한스, 그래 당신이 맞아요. 그러나이 상황에서 일부 키의 이름을 바꾸고 싶습니다.
xgqfrms-gildata 1

2
이를 위해서는 훨씬 더 많은 코드가 필요하고 효율성이 떨어지며 새 객체를 만듭니다. 속성의 이름을 바꾸면 객체가 변경됩니다. 새로운 것이 항상 더 좋은 것은 아닙니다.
Jean Vincent


13

여기에있는 대부분의 답변은 JS 객체 키-값 쌍 순서를 유지하지 못합니다. 예를 들어 수정하려는 화면에 객체 키-값 쌍의 형태가있는 경우 객체 항목의 순서를 유지하는 것이 중요합니다.

JS 객체를 반복하고 키-값 쌍을 수정 된 키 이름을 가진 새 쌍으로 바꾸는 ES6 방식은 다음과 같습니다.

let newWordsObject = {};

Object.keys(oldObject).forEach(key => {
  if (key === oldKey) {
    let newPair = { [newKey]: oldObject[oldKey] };
    newWordsObject = { ...newWordsObject, ...newPair }
  } else {
    newWordsObject = { ...newWordsObject, [key]: oldObject[key] }
  }
});

솔루션은 이전 항목 대신 새 항목을 추가하여 항목 순서를 유지합니다.


완벽합니다, 이것이 내가 필요한 것입니다
p0358 December

12

lodash를 시도 할 수 있습니다 _.mapKeys.

var user = {
  name: "Andrew",
  id: 25,
  reported: false
};

var renamed = _.mapKeys(user, function(value, key) {
  return key + "_" + user.id;
});

console.log(renamed);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>


이 솔루션은 저에게 효과적이지만 항상 '핵심'변수를 반환하도록주의하십시오. 예 : if (key === 'oldKey') {return 'newKey'; } 리턴 키;
TomoMiha 19

12

객체 파괴 및 확산 연산자를 사용한 변형 :

    const old_obj = {
        k1: `111`,
        k2: `222`,
        k3: `333`
    };


// destructuring, with renaming. The variable 'rest' will hold those values not assigned to kA, kB, or kC.
    const {
        k1: kA, 
        k2: kB, 
        k3: kC,
        ...rest
    } = old_obj;


// now create a new object, with the renamed properties kA, kB, kC; 
// spread the remaining original properties in the 'rest' variable
const newObj = {kA, kB, kC, ...rest};

아마도 이것이 무엇을하고 어떻게 작동하는지 설명 할 수 있습니까?
Jon Adams

@JeffLowery 객체의 배열이라면 어떨까요? foreach를해야합니까, 아니면 확산으로도 할 수 있습니까?
user3808307

@ user3808307 배열 및 배열의 ​​개체에 대해 스프레드를 수행 할 수 있습니다.
Jeff Lowery

7

개인적으로 무거운 플러그인과 휠을 추가로 구현하지 않고 객체의 키 이름을 바꾸는 가장 효과적인 방법은 다음과 같습니다.

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

object = JSON.parse(str);

try-catch객체의 구조가 유효하지 않은 경우 래핑 할 수도 있습니다 . 완벽하게 작동합니다 :)


12
웁스! 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

4
이것은 속도와 어떻게 비교됩니까?
mix3d

16
또한 데이터 값의 어딘가에서 잠재적 인 문제가 발생하면 이전 키 이름과 동일한 문자열이됩니다.
mix3d

4
"완벽하게"의 특정 정의에 대해 "완벽하게 작동". 이름을 변경 시도 'a'{ a: 1, aa: 2, aaa: 3}이상 문자열이나 숫자 또는 논리 값보다 더 아무것도 있습니다 값으로 객체의 이름을 변경하려고, 또는 순환 참조하여보십시오.
rsp

1
객체에 함수 또는 날짜 객체가 포함되어 있으면 작동하지 않습니다.
ikhsan

7

각 키에 접두사를 추가하려면

const obj = {foo: 'bar'}

const altObj = Object.fromEntries(
  Object.entries(obj).map(([key, value]) => 
    // Modify key here
    [`x-${key}`, value]
  )
)

// altObj = {'x-foo': 'bar'}

5

나는 이런 식으로 할 것입니다 :

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

3
정적 키를 변환하지 않는 솔루션의 업데이트 버전 제작에 '정의되지 않은'여기 : gist.github.com/diasdavid/f8997fb0bdf4dc1c3543는 그럼에도 불구하고, 여전히 JSON의 여러 수준에서 키를 매핑하고자하는 문제 이상하지 않습니다 객체 (중첩 키를 다시 매핑), 아이디어?
David Dias

4

개념적 관점에서 오래된 객체 (웹 서비스의 객체)를 그대로두고 새 객체에 필요한 값을 넣는 것이 좋습니다. 클라이언트가 아니라면 적어도 서버에서 특정 지점을 다른 지점에서 추출한다고 가정합니다. 웹 서비스의 필드 이름과 동일한 필드 이름을 소문자로 사용하기로 한 사실은 실제로 이것을 변경하지 않습니다. 따라서 다음과 같은 작업을 수행하는 것이 좋습니다.

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

물론, 나는 여기에 모든 종류의 가정을하고 있는데, 사실이 아닐 수도 있습니다. 이것이 당신에게 적용되지 않거나 너무 느리다면 (그렇지 않습니까? 테스트하지 않았지만 필드 수가 증가함에 따라 차이가 작아지는 것을 상상해보십시오.)이 모든 것을 무시하십시오 :)

이 작업을 원하지 않고 특정 브라우저 만 지원해야하는 경우 새 getter를 사용하여 "uppercase (field)"도 반환 할 수 있습니다. http://robertnyman.com/2009/05/28 자세한 내용은 / getters-and-setters-with-javascript-code-samples-and-demos / 및 해당 페이지의 링크를 참조하십시오.

편집하다:

놀랍게도, 이것은 적어도 직장에서의 FF3.5에서 거의 두 배 빠릅니다. 참조 : http://jsperf.com/spiny001


노력해 주셔서 대단히 감사하지만 사용 사례는 정적 객체의 구조와 깊이를 알 수 없으므로 정적 객체를 조작하지 않습니다. 따라서 가능하면 질문의 원래 범위를 고수하고 싶습니다.
Jean Vincent

4

이것은 키 이름을 바꾸는 데 더 나은 솔루션을 제공하지는 않지만 객체에 포함 된 데이터를 변경하지 않고 객체의 모든 키 이름을 빠르고 쉽게 바꿀 수있는 ES6 방법을 제공합니다.

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

3
편집 링크를 사용 하여이 코드의 작동 방식을 설명하고 코드를 제공하지 마십시오. 설명은 향후 독자에게 도움이 될 것입니다. 답변 방법 도 참조하십시오 . 출처
Jed Fox

나는 동의한다. 특별히 질문에 대답하지는 않지만 객체의 모든 키 이름을 바꾸는 솔루션으로 작업을 수행하는 데 도움이되었습니다. 어쩌면 나는 그 주제를 놓쳤다 ..
Tudor Morar

3

이 페이지에 나열된 일부 솔루션에는 몇 가지 부작용이 있습니다.

  1. 객체의 키 위치에 영향을 미치고 맨 아래에 추가하십시오 (중요한 경우)
  2. IE9 +에서는 작동하지 않습니다 (다시 중요합니다)

다음은 같은 위치에 키 위치를 유지하고 IE9 +와 호환되지만 새 개체를 만들어야하며 가장 빠른 솔루션이 아닐 수있는 솔루션입니다.

function renameObjectKey(oldObj, oldName, newName) {
    const newObj = {};

    Object.keys(oldObj).forEach(key => {
        const value = oldObj[key];

        if (key === oldName) {
            newObj[newName] = value;
        } else {
            newObj[key] = value;
        }
    });

    return newObj;
}

참고 : IE9는 엄격 모드에서 각 기능을 지원하지 않을 수 있습니다


2

다음은 이름이 바뀐 키로 새 객체를 만드는 예입니다.

let x = { id: "checkout", name: "git checkout", description: "checkout repository" };

let renamed = Object.entries(x).reduce((u, [n, v]) => {
  u[`__${n}`] = v;
  return u;
}, {});

2

가장 강력한 REDUCE 방법을 사용하는 또 다른 방법입니다 .

data = {key1: "value1", key2: "value2", key3: "value3"}; 

keyMap = {key1: "firstkey", key2: "secondkey", key3: "thirdkey"};

mappedData = Object.keys(keyMap).reduce((obj,k) => Object.assign(obj, { [keyMap[k]]: data[k] }),{});

console.log(mappedData);


1

이것은 내가 pomber의 기능에 대한 작은 수정입니다. 객체 대신 객체 배열을 사용할 수 있고 색인을 활성화 할 수 있습니다. 또한 "키"는 배열에 의해 할당 될 수 있습니다

function renameKeys(arrayObject, newKeys, index = false) {
    let newArray = [];
    arrayObject.forEach((obj,item)=>{
        const keyValues = Object.keys(obj).map((key,i) => {
            return {[newKeys[i] || key]:obj[key]}
        });
        let id = (index) ? {'ID':item} : {}; 
        newArray.push(Object.assign(id, ...keyValues));
    });
    return newArray;
}

테스트

const obj = [{ a: "1", b: "2" }, { a: "5", b: "4" } ,{ a: "3", b: "0" }];
const newKeys = ["A","C"];
const renamedObj = renameKeys(obj, newKeys);
console.log(renamedObj);

1

내 의견으로는 당신의 방식은 최적화되어 있습니다. 그러나 재정렬 된 키로 끝납니다. 새로 생성 된 키가 끝에 추가됩니다. 나는 키 순서에 의존해서는 안된다는 것을 알고 있지만, 그것을 유지 해야하는 경우 모든 키를 거치고 새 객체를 하나씩 생성해야하며 해당 프로세스 중에 해당 키를 교체해야합니다.

이처럼 :

var new_o={};
for (var i in o)
{
   if (i==old_key) new_o[new_key]=o[old_key];
   else new_o[i]=o[i];
}
o=new_o;

0
  • 유틸리티를 사용하여이를 처리 할 수 ​​있습니다.
npm i paix
import { paix } from 'paix';

const source_object = { FirstName: "Jhon", LastName: "Doe", Ignored: true };
const replacement = { FirstName: 'first_name', LastName: 'last_name' };
const modified_object = paix(source_object, replacement);

console.log(modified_object);
// { Ignored: true, first_name: 'Jhon', last_name: 'Doe' };

0

좋아하는 편집기에서 사용해보십시오 <3

const obj = {1: 'a', 2: 'b', 3: 'c'}

const OLD_KEY = 1
const NEW_KEY = 10

const { [OLD_KEY]: replaceByKey, ...rest } = obj
const new_obj = {
  ...rest,
  [NEW_KEY]: replaceByKey
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.