JavaScript: Nesne Yeniden Adlandırma Anahtarı


299

Javascript nesnesindeki bir anahtarı yeniden adlandırmanın akıllı (yani optimize edilmiş) bir yolu var mı?

Optimize edilmemiş bir yol:

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

14
"Optimize edilmiş" ile ne demek istiyorsun? Bundan daha fazla hile yapabileceğini sanmıyorum; yerleşik "yeniden adlandırma" işlemi yoktur.
Sivri

9
Elde edebileceğin bu kadar. Uygulamamdaki diğer şeyler için endişe ediyorum. Ve btw, dizilerle değil nesnelerle uğraşıyorsunuz. JavaScript'te ilişkilendirilebilir diziler yoktur (katı anlamda).
Felix Kling

3
@Jean Vincent: Bu yavaş mı?
Felix Kling

8
Bu en optimize ve temel versiyonu
Livingston Samuel

4
Sürüm safari, numune test durumu @ dışındaki tüm modern tarayıcılarda en hızlı jsperf.com/livi-006
Livingston Samuel

Yanıtlar:


193

Bunu yapmanın en eksiksiz (ve doğru) yolu olduğuna inanıyorum:

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

Bu yöntem, yeniden adlandırılan özelliğin orijinal özellikle aynı şekilde davranmasını sağlar .

Ayrıca bana öyle geliyor ki, bunu bir fonksiyona / yönteme koyup içine koyma olanağının Object.prototypesorunuzla ilgisi yok.


1
Bu, tüm özellikleri koruyan gerçek artı ile güzel bir ES5'e özgü bir çözümdür. Yani bu "optimize edilmedi" ama ES5'te kesinlikle daha doğru.
Jean Vincent

6
yazma_hakkında_with_underscores'a karşı bazı şüphecilikle oylandı, ancak elbette bu soruyu soran kişiye bağlıydı. bence bu doğru yanıt.
Bent Cardan

3
Önemli olması durumunda, ES5'in bu özel kullanımının IE9 ve daha yeni bir çözüm olduğuna inanıyorum.
Scott Stafford

1
O.old_key varlığını doğrulayan bir doğrulama eklemenizi öneririm. Değiştirme: if (old_key !== new_key)to: if (old_key !== new_key && o[old_key])
jose

100

Çalışmayı bir işlevde sarabilir ve Objectprototipe atayabilirsiniz . Belki birden fazla yeniden adlandırma akışı yapmak için akıcı arayüz stilini kullanın.

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'e Özel

Keşke sözdizimi bu karmaşık olmasaydı ama kesinlikle daha fazla kontrole sahip olmak güzel.

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 bunun için üzgünüm, ancak hata basmış JS kodundan gerçekten bıktım, şu anda tüm tuhaflıklar hakkında bir Rehber ( github.com/BonsaiDen/JavaScript-Garden ) yazıyorum ( şimdi düzelttiğiniz dahil), bu beni bir tür rant moduna sokmuş olabilir;) (-1'i şimdi
kaldırdık

1
@Ivo - Prototipi genişletmenin neden kötü olduğunu açıklar mısınız? Bebeğin uzatılması için prototipler yapıldı!
ChaosPandion

5
@Ivo - Riskli olduğunu kabul ediyorum, ancak daha anlamlı bir koda yol açtığını hissetsem prototipi genişletmemi engelleyecek hiçbir şey yok. Her ne kadar bir özelliği numaralandırılamaz olarak işaretleyebilirsiniz bir ECMAScript 5 zihniyetten gelmeme rağmen Object.defineProperty.
ChaosPandion

3
@Ivo - Her zaman hasOwnPropertyözellikleri kontrol etmek ve for ... indöngüler içinde kullanmak için uygun bir uygulama varsa, Object genişletirsek neden önemlidir?
David Tang

2
Bu kod işe yarıyor, ancak yeni anahtar adı zaten mevcutsa, değeri trodden düşecek
Brandon Minton

83

Kaynak nesnenizi değiştiriyorsanız, ES6 bunu bir satırda yapabilir.

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

Veya yeni bir nesne oluşturmak istiyorsanız iki satır.

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

5
Deneyin: Object.assign'ı silin (o, {newKey: o.oldKey}). OldKey; Benim için iyi çalıştı
Tim

2
Neden []etrafında köşeli ayraç var newKey? Çözüm aslında bu olmadan çalışır.
Soumya Kanti

2
Tamam - cevabımı aldım. Bu ES6 özelliğidir. Benim gibi buna tökezleyen herkes için, burada iyi bir cevap var .
Soumya Kanti

1
Değişken adlarınız daha ayrıntılı olsaydı bu yanıt daha güçlü olurdu.
lowcrawler

1
Belki? Üzgünüm, ilk yorumumla ne düşündüğümü unutuyorum.
lowcrawler

42

Birinin bir özellik listesini yeniden adlandırması gerekirse:

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

Kullanımı:

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
bu cevap kabul edilmelidir, benim kullanım dava için harika çalıştı. Gereksiz dize ile Ülke Adları önek olan bir API yanıtı dönüştürmek zorunda kaldı. Nesneyi anahtar dizisine dönüştürdüm ve her anahtar aracılığıyla alt dize yöntemiyle
Akin Hwan

1
Eski anahtarı silmediği için bu güzel. Eski anahtarın silinmesi, anahtar adı değişmediyse anahtarı tamamen nesneden kaldırır. Benim örnekte, dönüştürme oldu my_object_propertyiçin myObjectPropertyzaman özelliği, tek-ifadeli ise, bununla birlikte, daha sonra anahtar uzaklaştırılmıştır. +1
blueprintchris

25

Sadece ES6(ES2015)yolu kullanmak istiyorum !

zamana ayak uydurmamız gerekiyor!

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

demo ekran kısayolu


1
Yanlış biçimlendirilmiş bir nesneyi yeniden yapılandırılmış bir nesneye dönüştürmek istediğinizde bunu daha temiz bir çözüm olarak buldunuz.
NJInamdar

5
İyi, ama bence const {k1: kA, k2: kB, k3: kC,} = old_obj yeterli mi? yayılmaya gerek yok (old_obj'ın bir kopyasını istemiyorsanız).
Hans

@Hans, evet haklısın. Ama bu durumda, bazı anahtarları yeniden adlandırmak istiyorum, bu yüzden onları yaymalıyım.
xgqfrms-gildata

2
Bu çok daha fazla kod gerektirir, daha az verimli olur ve yeni bir nesne oluşturur. Bir özelliğin yeniden adlandırılması, nesneyi değiştirmeyi gerektirir. Yeni olan her zaman daha iyi değildir.
Jean Vincent


13

Buradaki yanıtların çoğu JS Nesnesi anahtar / değer çiftleri sırasını koruyamaz. Ekranda değiştirmek istediğiniz bir nesne anahtar / değer çifti biçiminiz varsa, nesne girişlerinin sırasını korumak önemlidir.

JS nesnesinde döngü ve anahtar / değer çiftini değiştirilmiş bir anahtar adıyla yeni çiftle değiştirmenin ES6 yolu şöyle olacaktır:

let newWordsObject = {};

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

Çözüm, eskisinin yerine yeni girişi ekleyerek girişlerin sırasını korur.


Mükemmel, bu ihtiyacım olan şey
p0358

12

Lodash'ı deneyebilirsiniz _.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>


Bu çözüm benim için çalıştı, ancak her zaman bir 'anahtar' değişken döndürmeye dikkat edin. Örnek: if (key === 'oldKey') {return 'newKey'; } Geri dönüş tuşu;
TomoMiha

12

Nesne yok etme ve yayma işlecini kullanan bir varyasyon:

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

Belki bunun ne yaptığını ve nasıl çalıştığını açıklayabilirsiniz?
Jon Adams

@JeffLowery bir nesne dizisi olsaydı? Bir foreach yapmak zorunda mıyım yoksa forma ile de yapabilir miyim?
user3808307

@ user3808307 Bir dizi ve dizideki nesneler üzerinde bir forma yapabilirsiniz.
Jeff Lowery

7

Kişisel olarak, ekstra ağır eklentiler ve tekerlekler uygulamadan nesnedeki anahtarları yeniden adlandırmanın en etkili yolu:

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

object = JSON.parse(str);

try-catchNesneniz geçersiz bir yapıya sahipse bunu da içine alabilirsiniz . Mükemmel çalışıyor :)


12
ooops! var object = {b: '123', 'c': 'bbb'}; var str = JSON.stringify (nesne); str = str.replace (/ b / g, 'newKey'); str = str.replace (/ c / g, 'newKey2'); object = JSON.parse (str);
BlondinkaBrain

4
Bu hız ile nasıl karşılaştırılır?
mix3d

16
Ayrıca veri değerlerinde bir yerde potansiyel bir sorun içine çalışır eski anahtar adı ile aynı dizedir.
mix3d

4
"Mükemmel" in belirli tanımları için "mükemmel çalışır". Adlandırmak deneyin 'a'bölgesi { a: 1, aa: 2, aaa: 3}veya daha fazla dizeleri veya numaraları veya boolelerde daha bir şey değerlere sahip bir nesneyi yeniden adlandırmak deneyin veya dairesel referanslarla deneyin.
rsp

1
nesne işlev veya tarih nesnesi içeriyorsa, bu işe yaramaz
ikhsan

7

Her bir tuşa önek eklemek için:

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

Böyle bir şey yapardım:

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

3
Statik anahtarları burada 'tanımsız' değerine dönüştürmeyen güncellenmiş bir sürüm yaptı: gist.github.com/diasdavid/f8997fb0bdf4dc1c3543 Yine de, JSON'un çeşitli düzeylerinde anahtarları yeniden eşleştirme istemesi sorunu hala çözülmedi nesne (iç içe anahtarları yeniden eşleme), fikirler?
David Dias

4

Kavramsal bir bakış açısından eski nesneyi (web hizmetinden olanı) olduğu gibi bırakmanın ve ihtiyacınız olan değerleri yeni bir nesneye koymanın daha iyi olacağını söyleyebilirim. İstemcide değilse, en azından sunucuda, bir noktada veya başka bir yerde belirli alanları ayıkladığınızı varsayıyorum. Web hizmetindekilerle aynı olan alan adlarını, yalnızca küçük harf kullanmayı seçtiyseniz, bunu gerçekten değiştirmez. Yani, böyle bir şey yapmanızı tavsiye ederim:

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

Tabii ki, burada doğru olmayabilecek her türlü varsayımı yapıyorum. Bu sizin için geçerli değilse veya çok yavaşsa (test etmedim, ancak alan sayısı arttıkça farkın küçüldüğünü hayal ediyorum), lütfen bunların tümünü göz ardı edin :)

Bunu yapmak istemiyorsanız ve yalnızca belirli tarayıcıları desteklemeniz gerekiyorsa, yeni alıcıları da "büyük harf (alan)" döndürmek için de kullanabilirsiniz: bkz. Http://robertnyman.com/2009/05/28 / getters-and-setters-with-javascript-code-samples-and-demolar / ve daha fazla bilgi için bu sayfadaki bağlantılar.

DÜZENLE:

İnanılmaz bir şekilde, bu aynı zamanda neredeyse iki kat daha hızlı, en azından benim işyerindeki FF3.5'imde. Bkz. Http://jsperf.com/spiny001


Çabalarınız için çok teşekkür ederim, ancak kullanım durumu, statik nesneleri yapıları ve derinlikleri bilinmediği için manipüle etmiyor. Bu yüzden mümkünse sorunun orijinal kapsamına bağlı kalmak istiyorum.
Jean Vincent

4

Bu, bir anahtarı yeniden adlandırmak için tam olarak daha iyi bir çözüm sunmasa da, içerdikleri verileri mutasyona uğratmadan bir nesnedeki tüm anahtarları yeniden adlandırmanın hızlı ve kolay bir ES6 yolu sağlar.

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

3
Bu kodun nasıl çalıştığını açıklamak için lütfen düzenle bağlantısını kullanın ve sadece kodu vermeyin, çünkü bir açıklama gelecekteki okuyuculara yardımcı olma olasılığı daha yüksektir. Ayrıca bkz . Nasıl Cevap Verilir . kaynağı
Jed Fox

Katılıyorum. Soruyu özel olarak cevaplamıyor, ancak işin nesnedeki tüm anahtarları yeniden adlandırmak için bir çözüm olarak yapılmasına yardımcı oldu. Belki konuyu kaçırdım ..
Tudor Morar

3

Bu sayfada listelenen çözümlerin bazılarının bazı yan etkileri vardır:

  1. anahtarın nesnedeki konumunu etkiler, tabana ekler (bu sizin için önemliyse)
  2. IE9 + 'da çalışmaz (yine, bu sizin için önemliyse)

Anahtarın konumunu aynı yerde tutan ve IE9 + 'da uyumlu olan, ancak yeni bir nesne oluşturmak zorunda olan ve en hızlı çözüm olmayabilecek bir çözüm:

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

Lütfen dikkat: IE9 katı modda her desteği desteklemeyebilir


2

Yeniden adlandırılmış anahtarlarla yeni bir nesne oluşturmak için bir örnek.

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

En güçlü REDUCE yöntemi ile başka bir yol .

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

Bu, bombacının işlevinde yaptığım küçük bir değişikliktir; Yalnızca bir nesne yerine bir Nesne Dizisi alabilmek ve ayrıca dizini etkinleştirebilirsiniz. ayrıca "Anahtarlar" bir dizi tarafından atanabilir

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

Ölçek

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

Bence yolunuz optimize edildi. Ama yeniden sıralanmış anahtarlarla sonuçlanacaksınız. Yeni oluşturulan anahtarın sonuna eklenir. Asla anahtar düzene güvenmemeniz gerektiğini biliyorum, ancak korumanız gerekiyorsa, tüm anahtarları gözden geçirmeniz ve söz konusu işlem sırasında söz konusu anahtarı değiştirerek yeni bir nesne oluşturmanız gerekir.

Bunun gibi:

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
  • Bunu işlemek için bir yardımcı program kullanabilirsiniz.
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

sadece en sevdiğiniz editörde deneyin <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
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.