Bir değişkenin değerini başka birine kopyalayın


102

Değer olarak JSON nesnesi olan bir değişkenim var. Bu değişkeni doğrudan başka bir değişkene atıyorum, böylece aynı değeri paylaşıyorlar. Bu nasıl çalışır:

var a = $('#some_hidden_var').val(),
    b = a;

Bu çalışır ve her ikisi de aynı değere sahiptir. Uygulamam üzerinden mousemovegüncelleme byapmak için bir olay işleyici kullanıyorum . Bir düğme tıklandığında, borijinal değere, yani içinde depolanan değere geri dönmek istiyorum a.

$('#revert').on('click', function(e){
    b = a;
});

Bundan sonra, aynı mousemoveolay işleyicisini kullanırsam, her ikisini de günceller ave bdaha önce yalnızca bbeklendiği gibi güncellenirken .

Bu konuda şaşkına döndüm! Burada sorun ne?


Lütfen fare işleyicinizi gösterin. Ayrıca, taşıdığı açıktır agelen kuruldu .val()bu doğru - Öyle olmadığını bir nesne JSON (bir dize), olduğunu varsayalım? JSON.parse(a)Bir noktada gerçek bir nesne elde etmek için kullanıyor musunuz ?
nnnnnn

Evet bu bir dizge ama $.parseJSONonu bir nesneye dönüştürmek için kullanıyorum . Yapı: { 'key': {...}, 'key': {...}, ...}. Maalesef buraya herhangi bir kod gönderemem, işyerimde izin verilmiyor!
Rutwick Gangurde

1
böylece bir aamacı,?
Armand

1
Kapsam belirleme sorunu gibi görünüyor .. aglobal bir değişken mi?
msturdy

2
Gösterdiğiniz kodda yalnızca dizeler var. Nesnelerden bahsediyorsanız, birden çok değişken aynı nesneye başvurabilir ve böylece nesne, değişkenlerin herhangi biri aracılığıyla değiştirilebilir. Bu nedenle, değişkenleri manipüle eden daha fazla kod görmeden ( $.parseJSON()bunun içine nereden giriyor?) Sorunun ne olduğunu söylemek zor. İşyeri kurallarınızla ilgili olarak, gerçek gerçek kodunuzu tam olarak yayınlamanız gerekmez, sorunu gösteren daha kısa ve daha genel bir örnek bulun (ve ideal olarak jsfiddle.net'teki canlı bir demoya bir bağlantı ekleyin ) .
nnnnnn

Yanıtlar:


205

=JavaScript'teki operatörün ne yaptığını ve yapmadığını anlamak önemlidir .

=Operatör bir yapmaz kopya verilerinin.

=Operatör yeni yaratır başvuru için aynı verilere.

Orijinal kodunuzu çalıştırdıktan sonra:

var a = $('#some_hidden_var').val(),
    b = a;

ave bşimdi aynı nesne için iki farklı isim var .

Bu nesnenin içeriğinde yaptığınız herhangi bir değişiklik, ister adeğişken ister değişken üzerinden başvuruyor olun, aynı şekilde görülecektir b. Aynı nesnelerdir.

Dolayısıyla, daha sonra bu kodla borijinal anesneye "geri dönmeyi" denediğinizde :

b = a;

Kod aslında hiçbir şey yapmaz , çünkü ave btamamen aynı şeydir. Kod, yazdığınızla aynıdır:

b = b;

ki belli ki hiçbir şey yapmayacak.

Yeni kodunuz neden çalışıyor?

b = { key1: a.key1, key2: a.key2 };

Burada, {...}nesne değişmeziyle yepyeni bir nesne yaratıyorsunuz . Bu yeni nesne, eski nesnenizle aynı değil. Yani şimdi istediğinizi byapan bu yeni nesneye referans olarak ayarlıyorsunuz .

Herhangi bir rastgele nesneyi işlemek için, Armand'ın cevabında listelenen gibi bir nesne klonlama işlevini kullanabilirsiniz veya jQuery'yi kullandığınız için yalnızca $.extend()işlevi kullanın . Bu işlev, bir nesnenin basit bir kopyasını veya derin bir kopyasını oluşturur. (Bunu , nesneleri değil, DOM öğelerini kopyalamak için kullanılan $().clone()yöntemle karıştırmayın .)

Sığ bir kopya için:

b = $.extend( {}, a );

Veya derin bir kopya:

b = $.extend( true, {}, a );

Sığ kopya ile derin kopya arasındaki fark nedir? Yüzeysel bir kopya, bir nesne değişmeziyle yeni bir nesne oluşturan kodunuza benzer. Orijinal nesneyle aynı özelliklere referanslar içeren yeni bir üst düzey nesne oluşturur.

Nesneniz yalnızca sayılar ve dizeler gibi ilkel türleri içeriyorsa, derin bir kopya ve yüzeysel bir kopya tam olarak aynı şeyi yapacaktır. Ancak nesneniz başka nesneler veya içinde yuvalanmış diziler içeriyorsa, sığ bir kopya bu yuvalanmış nesneleri kopyalamaz , yalnızca onlara referanslar oluşturur. Böylece, üst düzey nesnenizde yaşadığınız iç içe nesnelerle aynı sorunu yaşayabilirsiniz. Örneğin, bu nesne verildiğinde:

var obj = {
    w: 123,
    x: {
        y: 456,
        z: 789
    }
};

Bu xnesnenin basit bir kopyasını yaparsanız , yeni nesnenizin özelliği xorijinalle aynı nesnedir:

var copy = $.extend( {}, obj );
copy.w = 321;
copy.x.y = 654;

Şimdi nesneleriniz şöyle görünecek:

// copy looks as expected
var copy = {
    w: 321,
    x: {
        y: 654,
        z: 789
    }
};

// But changing copy.x.y also changed obj.x.y!
var obj = {
    w: 123,  // changing copy.w didn't affect obj.w
    x: {
        y: 654,  // changing copy.x.y also changed obj.x.y
        z: 789
    }
};

Bunu derin bir kopya ile önleyebilirsiniz. Derin kopya, üst düzey nesnenin bir kopyasını oluşturduğu şekilde bu nesnelerin kopyalarını oluşturmak için her yuvalanmış nesneye ve diziye (ve Armand'ın kodundaki Tarih) yinelenir. Yani değişiklik copy.x.yetkilemeyecek obj.x.y.

Kısa cevap: Şüpheniz varsa, muhtemelen derin bir kopya istersiniz.


Teşekkürler, aradığım buydu. Etrafında çalışmanın bir yolu var mı? Şu anki durumumda, sadece 2 özelliğim olduğu için düzeltmek kolaydı. Ancak daha büyük nesneler olabilir.
Rutwick Gangurde

1
Armand'ın cevabı, hile yapacak bir nesne klonlama işlevine sahiptir. Veya jQuery kullandığınız için yerleşik $.extend()işlevi kullanabilirsiniz. Yukarıdaki ayrıntılar. :-)
Michael Geary

Harika açıklama Michael!
Rutwick Gangurde

8
@MichaelGeary Nitpicking olabilir, ancak kural yalnızca nesnelere ve ilkel değişkenlere uygulanmıyor mu? cevapta
Jonathan dos Santos

Buna JS çözümü, Michael Geary'nin dediği gibi Armands yanıtında. =
AlexanderGriffin

57

JSON çalışmalarını kullanarak buldum ama döngüsel referanslarımızı izleyin

var newInstance = JSON.parse(JSON.stringify(firstInstance));

2
Bunun biraz geç olduğunun farkındayım, ancak bu yöntemle ilgili bir sorun mu var? İlk denemede harika çalışıyor gibi görünüyor.
Mankind1023

2
Bu hemen hemen her durumda harikadır, ancak özel olma potansiyeline sahip verilerle çalışıyorsanız, programınızı çökertecektir. gösterilecek bazı kodlar: let a = {}; let b = {a:a}; a.b = b; JSON.stringify(a)bir TypeError verecek
schu34

Bu çözüm harika çalışıyor. Ancak, bu işlem sırasında ne kadar pahalıdır? Görünüşe göre bu çifte olumsuzlama ile çalışıyor.
Abel Callejo

30

Bu soru çok uzun zamandan beri çözüldü, ancak ileride başvurmak için olası bir çözüm

b = a.slice(0);

Dikkatli olun, bu yalnızca a iç içe olmayan bir sayı ve dizge dizisi olduğunda doğru çalışır


28

newVariable = originalVariable.valueOf();

kullanabileceğiniz nesneler için, b = Object.assign({},a);


3
kullanabileceğiniz nesneler için, b = Object.assign ({}, a);
Kishor Patil

15

Bunun nedeni basit. JavaScript referansları kullanır, bu yüzden atadığınızda b = abir referans atarsınız , bböylece güncelleme yaparken de güncelleme ayaparsınızb

Bulduğum bu stackoverflow ve bir nesnenin derin bir kopyasını yapmak istiyorsanız sadece bu yöntemini çağırarak gelecekte bu gibi şeyler önlemeye yardımcı olacaktır.

function clone(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

Teşekkürler! Yeni bir soru göndermeden önce bu gönderiyi gördüm. Ama bunun senaryomda yardımcı olup olmayacağından emin değildim. Görünüşe göre ihtiyacım olan bu.
Rutwick Gangurde

İlki dışında hepsi if (obj instanceof x) { ... }başka olmamalı mı ?
Zac

@Zac Bu durumda değil. Her if-body (ilgilenilen) bir değer döndürür. (bir sonraki eğer işlevden önce çıkar)
Bitterblue

8

Cevapların neden bu kadar karmaşık olduğunu anlamıyorum. Javascript'te ilkeller (dizeler, sayılar vb.) Değere göre aktarılır ve kopyalanır. Diziler de dahil olmak üzere nesneler başvuruya göre aktarılır. Her durumda, yeni bir değerin atanması veya 'a' nesnesine referans verilmesi 'b'yi değiştirmeyecektir. Ancak "a" nın içeriğini değiştirmek "b" nin içeriğini değiştirecektir.

var a = 'a'; var b = a; a = 'c'; // b === 'a'

var a = {a:'a'}; var b = a; a = {c:'c'}; // b === {a:'a'} and a = {c:'c'}

var a = {a:'a'}; var b = a; a.a = 'c'; // b.a === 'c' and a.a === 'c'

Yukarıdaki satırlardan herhangi birini (birer birer) düğüme veya herhangi bir tarayıcı javascript konsoluna yapıştırın. Ardından herhangi bir değişkeni yazın ve konsol onun değerini gösterecektir.


4

Dizeler veya giriş değerleri için şunu kullanabilirsiniz:

var a = $('#some_hidden_var').val(),
b = a.substr(0);

Neden bir ilkeli alt yazarsınız? Sadece atayın, dizeyi kopyalar. Yalnızca nesneler ve diziler (nesnelerdir) başvuru ile iletilir.
Trenton D. Adams

3

Buradaki yanıtların çoğu yerleşik yöntemler veya kitaplıklar / çerçeveler kullanıyor. Bu basit yöntem iyi çalışmalıdır:

function copy(x) {
    return JSON.parse( JSON.stringify(x) );
}

// Usage
var a = 'some';
var b = copy(a);
a += 'thing';

console.log(b); // "some"

var c = { x: 1 };
var d = copy(c);
c.x = 2;

console.log(d); // { x: 1 }

Dahi! Diğer yöntemler, içlerindeki diziler dahil her şeyi sözlüğe çevirir. Bununla nesneyi klonladım ve içeriği bundan farklı olarak bozulmadan kalıyor:Object.assign({},a)
Tiki

0

Şimdilik kendim çözdüm. Orijinal değerin yalnızca 2 alt özelliği vardır. Özellikleriyle yeni bir nesneyi yeniden biçimlendirdim ave sonra ona atadım b. Artık yalnızca olay işleyicim güncellemeleri bve orijinala olduğu gibi kalıyor.

var a = { key1: 'value1', key2: 'value2' },
    b = a;

$('#revert').on('click', function(e){
    //FAIL!
    b = a;

    //WIN
    b = { key1: a.key1, key2: a.key2 };
});

Bu iyi çalışıyor. Yukarıdakiler dışında kodumun hiçbir yerinde tek bir satırı değiştirmedim ve tam istediğim gibi çalışıyor. Yani, güven bana, başka hiçbir şey güncellenmiyordu a.


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.