JavaScript:オブジェクトの名前変更キー


299

JavaScriptオブジェクトのキーの名前を変更する賢い(つまり最適化された)方法はありますか?

最適化されていない方法は次のとおりです。

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

14
「最適化」とはどういう意味ですか?それ以上簡潔になるとは思いません。「名前を変更する」組み込みの操作はありません。
先のとがっ

9
あなたが得ることができるのはそれだけです。アプリケーションで他のことを心配しました。ところで、あなたは配列ではなくオブジェクトを扱っています。JavaScriptには連想配列はありません(厳密には)。
Felix Kling、2011年

3
@ジャン・ヴィンセント:遅いですか?
Felix Kling、2011年

8
これは最も最適化された基本バージョンです
Livingston Samuel

4
あなたのバージョンは、サファリを除くすべての最新ブラウザーで最速です。サンプルテストケース@ 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への懐疑的な意見に賛成ですが、もちろんそれは質問をした人が原因でした。これは私の見解では正しい応答です。
Bent Cardan 2013

3
重要なことですが、ES5のこの特定の使用法はIE9以降のソリューションであると思います。
スコットスタッフォード

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コードに本当にうんざりしています。これは私をある種の暴言モードにしたかもしれません;)(今すぐ-1を削除しました)
Ivo Wetzel

1
@Ivo-プロトタイプの拡張が悪いと感じた理由を説明できますか?赤ちゃんを伸ばすためのプロトタイプが作られました!
ChaosPandion 2011年

5
@Ivo-危険であることに同意しますが、より表現力豊かなコードにつながると感じた場合にプロトタイプを拡張することを妨げるものは何もありません。私はECMAScript 5の考え方から来ていますが、ここで、プロパティを列挙不可としてマークできますObject.defineProperty
ChaosPandion 2011年

3
@Ivo- hasOwnPropertyプロパティのチェックとfor ... inループ内で常にを使用することが適切な方法である場合、Objectを拡張することが重要なのはなぜですか?
David Tang

2
このコードは動作しますが、注意点、新しいキー名が既に存在する場合、その値は踏まを降りしようとしていることである。jsfiddle.net/ryurage/B7x8x
ブランドンミントン

83

ソースオブジェクトを変更する場合、ES6は1行で変更できます。

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

または、新しいオブジェクトを作成する場合は2行。

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

5
試行:Object.assign(o、{newKey:o.oldKey})。oldKey;を削除します。私にとってはうまくいった
Tim

2
なぜ[]周りに角括弧があるのnewKeyですか?ソリューションは実際にそれなしで動作します。
Soumya Kanti

2
わかりました-私は私の答えを得ました。ES6の機能です。私のようにこれにつまずいた誰かのために、ここに良い答えがあります。
Soumya Kanti

1
変数名がより冗長である場合、この答えはより強力になります。
ロークローラ

1
たぶん?申し訳ありませんが、最初のコメントで何を考えていたか忘れてしまいました。
ロークローラー

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応答を変換する必要がありました。オブジェクトをキーの配列に変換し、サブストリングメソッドを使用して各キーにマップし、新しいキーと元のキーでインデックス付けされた値を持つ新しいオブジェクトを返しました
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 2018

5
良いものですが、const {k1:kA、k2:kB、k3:kC、} = old_objで十分ですか?(old_objのコピーが必要でない限り)拡散する必要はありません。
ハンス

@ハンス、ええ、あなたは正しいです。しかし、この状況では、いくつかのキーの名前を変更したいので、それらを広げる必要があります。
xgqfrms-gildata

2
これはより多くのコードを必要とし、効率が悪くなり、新しいオブジェクトを作成します。プロパティの名前を変更すると、オブジェクトが変更されます。新しい方が常に良いとは限りません。
Jean Vincent


13

ここでの答えのほとんどは、JSオブジェクトのキーと値のペアの順序を維持できません。たとえば、変更する画面にオブジェクトのキーと値のペアの形式がある場合、オブジェクトエントリの順序を維持することが重要です。

ES6がJSオブジェクトをループし、キーと値のペアを変更されたキー名を持つ新しいペアで置き換える方法は次のようになります。

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

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

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

おそらく、これが何をしていて、どのように機能するかを説明できますか?
ジョンアダムス

@JeffLoweryそれがオブジェクトの配列である場合はどうなりますか?foreachを実行する必要がありますか、それともスプレッドで実行できますか?
user3808307

@ user3808307配列、および配列内のオブジェクトに対して分散を行うことができます。
ジェフロウリー

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(object); str = str.replace(/ b / g、 'newKey'); str = str.replace(/ c / g、 'newKey2'); オブジェクト= JSON.parse(str);
BlondinkaBrain、2016

4
これはどのように速度を比較しますか?
mix3d 2016年

16
また、データ値のどこかに古いキー名と同じ文字列があるという潜在的な問題が発生します。
mix3d 2016年

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

古いオブジェクト(Webサービスからのもの)をそのままにして、必要な値を新しいオブジェクトに入れる方が、概念的な観点からは良いと思います。とにかく、クライアントではなくても、少なくともサーバーで、特定のフィールドをとにかく抽出することを想定しています。Webサービスのものと同じで小文字のみのフィールド名を使用することを選択したという事実は、実際にはこれを変更しません。だから、私はこのようなことをすることをお勧めします:

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 /および詳細については、そのページのリンク。

編集:

信じられないことに、これは少なくとも私の仕事中のFF3.5では、ほぼ2倍の速さです。参照: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、

同意する。それは具体的な質問には答えませんが、オブジェクト内のすべてのキーの名前を変更するための解決策として仕事を成し遂げるのに役立ちました。多分私はトピックを逃した..
チューダーモラー

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は、strictモードのforEachをサポートしない場合があります


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

私の意見では、あなたの方法は最適化されています。ただし、キーの順序が変更されてしまいます。新しく作成されたキーは最後に追加されます。キーの順序に依存するべきではないことは承知していますが、それを保持する必要がある場合は、すべてのキーを調べ、新しいオブジェクトを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.