Bir javascript nesnesinden bir özellik nasıl kaldırılır?

Diyelim ki böyle bir nesne yarattım:

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*" }; 

regex özelliğini kaldırmanın, bunun gibi yeni bir myObject ile sonuçlanmanın en iyi yolu nedir:

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI" }; 
5276
16 окт. johnstok 16 ekim ayarla . 2008-10-16 13:57 '08, 13:57 2008-10-16 13:57
@ 37 cevaplar
  • 1
  • 2

İşte burada:

 delete myObject.regex; // or, delete myObject['regex']; // or, var prop = "regex"; delete myObject[prop]; 

gösteri

kangax , blogunda delete ifadesi hakkında Silme Anlaşması hakkında son derece ayrıntılı bir blog yazısı yazdı.  Şiddetle tavsiye edilir. 

7292
16 окт. cevap 16 ekim nickf veriliyor . 2008-10-16 13:58 '08, 13:58, 2008-10-16 13:58

Operatör delete beklenmedik şekilde yavaşlıyor!

Kriterlere bak.

Sil, bir nesnenin özelliklerini kalıntı bırakmadan kaldırmanın tek kesin yoludur, ancak "alternatif" ayar object[key] = undefined karşılaştırıldığında ~ 100 kat daha yavaş çalışır object[key] = undefined .

Bu alternatif, bu sorunun doğru cevabı değil! Ancak, dikkatli kullanırsanız, bazı algoritmaları önemli ölçüde hızlandırabilirsiniz. delete döngüler halinde kullanıyorsanız ve performans sorunlarınız varsa, ayrıntılı açıklamayı okuyun.

delete ne zaman kullanılmalı ve belirtilen değer ne zaman undefined ?

Bir nesne, bir anahtar-değer çiftleri kümesi olarak düşünülebilir. "Değer" dediğim şey, bu "anahtar" ile ilişkilendirilen başka bir nesneye ilişkin ilkel veya referanstır.

Bir sonuç nesnesini kontrol edemediğiniz bir koda (veya ekibinize veya kendinize güvenmediğiniz) geçerken delete kullanın .

Anahtarı karma karttan çıkarır .

  var obj = { field: 1 }; delete obj.field; 

Performanstan emin değilseniz undefined seçeneğini kullanın . Bu, kodunuzu ciddi şekilde etkileyebilir.

Anahtar hashmap'taki yerinde kalır , sadece değer undefined ile değiştirilir. for..in döngüsünün hala bu anahtardan geçeceğini anlayın.

  var obj = { field: 1 }; obj.field = undefined; 

Bu yöntemi kullanarak , varlık özelliğini belirlemeye yönelik tüm yöntemler beklendiği gibi çalışmaz.

Ancak bu kod:

object.field === undefined

Her iki yöntem için de aynı şekilde davranacaktır.

testler

Özetle, bir özelliğin varlığını belirleme şekillerinde for..in döngüsünde farklılıklar vardır.

border=0
  console.log('* -> "Takes prototype inheritance into consideration, that means it lookups all over prototype chain too."'); console.log(obj.field === undefined, 'obj.field === undefined', 'You get "undefined" value when querying for "field" in object-hashmap. *'); console.log(obj["field"] === undefined, 'obj["field"] === undefined', 'Just another way to query (equivalent). *'); console.log(typeof obj.field === "undefined", 'typeof obj.field === "undefined"', 'Get the value attached to "field" key, and check it\ type is "undefined". *'); console.log("field" in obj, '"field" in obj', 'This statement returns true if "field" key exists in the hashmap. False otherwise. *'); console.log(obj.hasOwnProperty("field"), 'obj.hasOwnProperty("field")', 'This statement returns true if \'field\' key exists in the hashmap. The ONLY way NOT to lookup for property in the prototype chain!'); //Object.keys().indexOf() is an overkill that runs much slower :) var counter = 0, key; for (key in obj) { counter++; } console.assert(counter === 0, 'counter === 0', '"field" is not iterated using "for .. in" loop. *'); 

Bellek sızıntılarına dikkat edin!

Her ne kadar obj[prop] = undefined delete obj[prop] daha hızlı olsa da, bir diğer önemli husus obj[prop] = undefined her zaman ilgili olmayabilir. delete obj[prop] , obj kaldırır ve bellekten siler; obj[prop] = undefined ise prop değerini obj[prop] = undefined olarak ayarlar undefined bu da prop hala bellekte bırakır. Bu nedenle, oluşturulan ve silinen birçok anahtarın olduğu durumlarda, obj[prop] = undefined kullanılması, pahalı bellek tutarlılığına (sayfanın donmasına neden olabilir) ve potansiyel olarak bellekte bir hataya yol açabilir. Aşağıdaki kodu inceleyin.

 "use strict"; var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[]; for (i = 0; i !== numberOfNodes; i++) { nodeRecords[i] = []; current = theNodeList[i] = document.createElement("div"); current.textContent = i; document.body.appendChild( current ); } var lastTime = -1; requestAnimationFrame(function recordUpdates(){ var currentTime = Math.round( performance.now()*1000 ) for (i = 0; i !== numberOfNodes; i++) { if (lastTime !== -1) { // the previously collected data is no longer in use   nodeRecords[i][lastTime] = undefined;   } nodeRecords[i][currentTime] = theNodeList[i].outerHTML; } lastTime = currentTime; requestAnimationFrame( recordUpdates ); }); 

Yukarıdaki kodda, sadece nodeRecords[i][lastTime] = undefined; Her animasyon karesinden dolayı büyük bir hafıza sızıntısına neden olacaktır. Her kare, 65536 DOM'un tüm elemanları bir başka 65.536 ayrı yuva alacaktır, fakat önceki 65.536 yuvaları sadece tanımsız olarak ayarlanacak ve bu da onları bellekte asılı bırakacaktır. Devam et, yukarıdaki kodu konsolda çalıştırmayı dene ve kendin gör. Zorunlu bir hafıza hatasından sonra, bunun yerine delete operatörünü kullanan kodun bir sonraki sürümü haricinde tekrar çalıştırmayı deneyin.

 "use strict"; var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[]; for (i = 0; i !== numberOfNodes; i++) { nodeRecords[i] = []; current = theNodeList[i] = document.createElement("div"); current.textContent = i; document.body.appendChild( current ); } var lastTime = -1; requestAnimationFrame(function recordUpdates(){ var currentTime = Math.round( performance.now()*1000 ) for (i = 0; i !== numberOfNodes; i++) { if (lastTime !== -1) { // the previously collected data is no longer in use   delete nodeRecords[i][lastTime];   } nodeRecords[i][currentTime] = theNodeList[i].outerHTML; } lastTime = currentTime; requestAnimationFrame( recordUpdates ); }); 

Yukarıdaki kod parçasından görülebileceği gibi, delete operatörü için bazı nadir uygun kullanımlar vardır. Ancak, bu sorun hakkında çok fazla endişelenmeyin. Bu sadece uzun ömürlü nesnelerde sorun yaratacaktır, ki bunlar onlara sürekli yeni anahtarlar eklemektedir. Başka bir durumda (bu gerçek programlamada hemen hemen her durumdur), obj[prop] = undefined kullanılması önerilir. Bu bölümün temel amacı, dikkatinizi sadece nadir durumlarda kodunuzda bir sorun haline geldiği gerçeğine çekmektir, o zaman sorunu daha kolay anlayabilirsiniz ve bu nedenle bu sorunu bulmak ve anlamak için kodunuzu analiz etmekle zaman kaybetmeyin.

Her zaman undefined ayarlanmadı

Javascript'in dikkate alınması gereken bir yönü polimorfizmdir. Polimorfizm, aşağıda gösterildiği gibi farklı türdeki nesnelerde aynı değişkenlerin / slotların atanmasıdır.

 var foo = "str"; foo = 100; // variable foo is now labeled polymorphic by the browser var bar = ["Some", "example"]; bar[2] = "text"; // bar is a monomorphic array here because all its entries have the // same type: string primitive bar[1] = undefined; // bar is now a polymorphic array 

Bununla birlikte, polimorfik diziler kullanılırken giderilemeyecek iki ana sorun vardır:

  1. Yavaş ve etkisizdirler. Belirli bir dizine erişirken, yalnızca bir dizinin genel türünü almak yerine, tarayıcı bunun yerine, her dizinin türünün ek meta verilerini depoladığı bir dizini temel alan bir tür almalıdır.
  2. Polimorfikten sonra daima polimorfiktir. Bir dizi polimorfik yapıldığında, Webkit tarayıcılarında polimorfizm iptal edilemez. Bu nedenle, polimorfik olmayan bir diziyi polimorfik olmayan bir şekilde geri yükleseniz bile, tarayıcı tarafından polimorfik bir dizi olarak saklanacaktır.

Uyuşturucu bağımlılığının polimorfizmini görebilirsiniz. İlk bakışta, inanılmaz karlı görünüyor: güzel, oldukça kabarık bir kod. Kodlayıcı daha sonra dizisine bir polimorfizm ilacına girer. Anında, polimorfik bir matris daha az etkili hale gelir ve anestezi uygulandığı için asla eskisi kadar etkili olamaz. Bu durumu gerçek hayatla ilişkilendirmek için, kokainden birileri basit bir kapı kolunu bile kullanamayabilir, PI sayılarını daha az hesaplayabilir. Benzer şekilde, bir polimorfizm preparasyonundaki bir dizi, monomorfik bir dizi kadar etkili olamaz.

Fakat ilaç analojisi delete işlemine nasıl atıfta bulunur? Cevap, yukarıdaki kod parçasındaki son kod satırını içerir. Öyleyse, bu sefer bir bükümle revize edilsin.

 var bar = ["Some", "example"]; bar[2] = "text"; // bar is not a polymorphic array here because all its entries have the // same type: string primitive bar[1] = ""; // bar is still a monomorphic array bar[1] = undefined; // bar is now a polymorphic array 

Dikkat et bar[1] = "" bar[1] = undefined polimorfizme neden olmaz, oysa bar[1] = undefined . Bu nedenle, mümkün olduğunda, polimorfizme kazara neden olmamak için nesnelerinize uygun türü kullanmak her zaman gereklidir. Böyle bir kişi, aşağıdaki listeyi genel bir link olarak kullanmak için kullanabilir. Ancak, lütfen aşağıdaki fikirleri kullanmayın. Bunun yerine, kodunuz için en iyi olanı kullanın.

  • Boolean ilkelinde girilen bir dizi / değişken kullanırken, false veya undefined değerini boş bir değer olarak kullanın. Gereksiz polimorfizmden kaçınmak iyidir, ancak tüm kodunuzu açıkça devre dışı bırakmak için yeniden yazmak, performansın düşmesine neden olabilir. Sesli yargı kullanın!
  • Sayısal ilkelde girilen bir dizi / değişken kullanırken, 0 değerini boş değer olarak kullanın. İçinde iki tür sayı olduğuna dikkat edin: hızlı tam sayılar (2147483647 - -2147483648 dahil) ve yavaş çift kayan nokta noktaları ( NaN ve Infinity dışında herhangi bir şey). Bir tam sayı iki katına düştüğünde tam sayı olarak sınıflandırılamaz.
  • İlkel bir dizgeye girilen bir dizi / değişken kullanırken, boş değer olarak "" kullanın.
  • Sembolü kullanırken, bekleyin, neden Sembolü kullanıyorsunuz? Performans için kötü juju karakterleri. Kullanmak üzere programlanan tüm karakterler, daha hızlı kodsuz kodla sonuçlanan karakterleri kullanmamak üzere yeniden programlanabilir. Semboller gerçekten sadece etkisiz bir meta-şekerdir.
  • Başka bir şey kullanırken null kullanın.

Ancak, dikkatli ol! Böyle bir kodu kırmanız ve / veya garip hatalar ortaya koyması muhtemel olduğundan, bunu mevcut tüm kodlarla yapmaya başlamayın. Daha ziyade, böyle etkili bir uygulama en baştan itibaren uygulanmalıdır ve mevcut kodu dönüştürürken, eski kodu bu yeni uygulamaya güncellemeye yönelik bir girişim olarak, bununla ilgili tüm satırların dörtlü, üçlü kontrollerinin yapılması yararlı olabilir. .

770
12 февр. Yanıtla Dan 12 Şub 2014-02-12 20:48 '14 20:48, 2014-02-12 20:48

215
16 окт. Cevap 16 ekim redsquare tarafından verilir . 2008-10-16 14:03 '08, 02:03 de 2008-10-16 14:03

2018-07-21 Güncellemesi: Uzun süredir bu cevaptan utanmıştım, bu yüzden ona biraz dokunduğumu düşünüyorum. Bu cevabın gereksiz uzun ve kafa karıştırıcı kısımlarının okunmasını hızlandırmak için sadece küçük bir yorum, açıklama ve biçimlendirme.


KISA SÜRÜM

Sorunun asıl cevabı

Diğerlerinin dediği gibi, delete kullanabilirsiniz.

 obj // {"foo": "bar"} delete obj["foo"] obj // {} obj["foo"] // undefined 

Massive eşdeğeri

Diziden delete . Array.prototype.splice bu kullanımın Array.prototype.splice .

 arr // [1,2,3,4,5] arr.splice(3,1); // 4 arr // [1,2,3,5] 

UZUN SÜRÜM

JavaScript bir OOP dilidir, yani diziler de dahil olmak üzere her şey bir nesnedir. Bu nedenle, belirli bir uyarıya işaret etmenin gerekli olduğunu düşünüyorum.

Dizilerde, basit eski nesnelerin aksine, delete , null bırakır, dizide bir "delik" oluşturur.

 var array = [1, 2, 3, 4]; delete array[2];  

Gördüğünüz gibi, delete işlemi her zaman beklendiği gibi çalışmaz. Değerin üzerine yazılır, ancak bellek yeniden dağıtılmaz. Başka bir deyişle, array[4] array[3] taşınmıyor. Array.prototype.unshift aksine, bir dizinin başına bir öğe ekler ve her şeyi yukarı kaydırır ( array[0] , array[1] , vb.),

Dürüst olmak gerekirse, null ve undefined olmayan ayarlara ek olarak - ki bu tamamen garip - bu davranış şaşırtıcı olmamalıdır, çünkü delete dili, katı bir şekilde bükülmüş olan ve kullanılan nesnenin türünü umursamayan, typeof gibi unary bir operatördür. Array , dizilerle çalışmak için özel olarak tasarlanmış yöntemlerle bir Object alt sınıfıdır. Bu nedenle, delete işleminin bir diziyi yeniden değiştirmek için özel bir durum hazırlaması için bir neden yoktur, çünkü bu gereksiz işleri yapmadan işleri yavaşlatır. Geriye dönüp baktığımda beklentilerim gerçekçi değildi.

Tabii ki beni şaşırttı. Çünkü "sıfır çöp" e karşı haçlı seferimi haklı çıkarmak için yazdım:

null ve null alandaki doğal tehlikeleri ve sorunları göz ardı ederek, dizinin kesin olması gerekiyorsa bu sorunlu olabilir.

null s'den kurtulmak için korkunç bir bahane olan - null yalnızca yanlış kullanılırsa ve "doğruluk" ile ilgisi yoksa tehlikelidir. Bir diziden delete asıl sebebi, atıklarla dolu ve kirli veri yapılarını etrafta dağınık ve hataya eğilimli olması.

Aşağıda oldukça uzun süren bir kod yazılmıştır, bu nedenle isterseniz “Çözüm” bölümüne gidebilirsiniz. Bu bölümden ayrılmamın tek nedeni, bazı insanların muhtemelen komik bulduklarını düşünüyorum ve “komik” cevabını gönderen ve sonra silen “adam” olmak istemiyorum. hepsi "komik",

... Bu aptalca biliyorum.

Kararlı ve uzun vadeli senaryo PDP-11

Örneğin, dize sekmelerinde kullanılan diziyi saklamak için JSON serileştirmesini kullanan bir webapp oluşturduğunuzu varsayalım (bu durumda localStorage ). Ayrıca, kodun ekranda çizerken bunları "adlandırma" için dizi öğelerinin sayısal dizinlerini kullandığını da söyleyelim. Neden bunu yapıyorsun ve sadece "unvanını" muhafaza etmiyorsun? Çünkü ... sebepler.

Pekala, 1960’dan beri PDP-11 minibilgisayarını çalıştıran, UNIX’i çalıştıran ve JavaScript’le JavaScript destekli kendi JavaScript uyumlu arabirimini yazan bu kullanıcının isteği üzerine bellek tasarrufu yapmaya çalıştığınızı söyleyeyim, çünkü X11 söz konusu değil.

Belirtilen dizide delete kullanarak marjinal betiğin gittikçe aptalca bir dizisi dizinin kirlenmesini boşaltacaktır ve daha sonra uygulamada hatalara yol açması muhtemeldir. Ve null değerini kontrol ederseniz, otomatik olarak sayıları atlar, sonuçta görüntülenen sekmeler [1] [2] [4] [5]...

 if (array[index] == null) continue; else title = (index + 1).toString();  

Evet, kesinlikle istediğin bu değil.

Artık ikinci yineleyiciyi, örneğin j , yalnızca gerçek değerler diziden okunduğunda artışa kaydedebilirsiniz. Ama kesinlikle null sorunu çözmüyor ve hala bu Troll PDP-11 kullanıcısını seviyorsunuz. Ne yazık ki, bilgisayarı basitçe bu son tamsayıyı saklamak için yeterli belleğe sahip değil (değişken genişlikteki bir diziyi nasıl idare edeceğini sorma ...) .

Bu yüzden sana kızgın bir mektup yolladı:

 Hey, your webapp broke my browser! I checked my localStorage database after your stupid code made my browser segfault, and this is what I found: >"tabs:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ... ]" After clearing my precious data, it segfaulted again, and I did a backtrace, and what do I find? WHAT DO I FIND!? YOU USE TOO MANY VARIABLES! >var i = index; >var j = 1; Grr, I am angry now. -Troll Davidson 

Şimdi sonunda sen varsın. Bu adam başvurunuzdan sürekli olarak şikayet etti ve sizden ona çenesini kapatmasını ve en iyi bilgisayara gitmesini söyle.

Çözüm: Array.prototype.splice

Neyse ki, dizilerin indeksleri çıkarmak ve belleği yeniden tahsis etmek için özel bir metodu var: Array.prototype.splice() . Böyle bir şey yazabilirsiniz:

 Array.prototype.remove = function(index){ this.splice(index,1); } ... array = [1, 2, 3, 4]; array.remove(2); // Result -> [1, 2, 4] 

Ve aynen böyle, Bay PDP-11’den memnunsunuz. Yaşasın! (Yine de ona söylerdim ...)

Array.prototype.splice vs Array.prototype.slice

Her ikisi de çok faydalı olduklarından, benzer adlandırılmış iki işlev arasındaki farkı not etmeyi önemli buluyorum.

Dizi.prototype.splice (baş>

.splice() bir diziyi değiştirir ve uzak dizinleri döndürür. Dizi indeksten başlayarak kesilir, start ve n elemanları kesilir. N belirtilmezse, start sonra dizinin tamamı n = array.length - start ( n = array.length - start ).

 let a = [5,4,3,2,1]; let chunk = a.splice(2,2); // a [5,4,3,2,1] // start 0 1 2 - - // n - - 1 2 - chunk; // [3,2] a; // [5,4,1] 

Array.prototype.slice (baş>

.slice() tahribatsızdır ve belirtilen endeksleri start end içeren yeni bir dizi döndürür. end belirtilmemişse, davranış .splice() aynı olacaktır ( end = array.length ). Davranış biraz karmaşık, çünkü bazı nedenlerden dolayı endeksler 0 yerine 1'den başlıyor. Bunun neden olduğunu bilmiyorum, ama öyle. Ek olarak, eğer end <= start ise sonuç boş bir dizidir.

 let a = [5,4,3,2,1]; let chunks = [ a.slice(2,0), a.slice(2,2), a.slice(2,3), a.slice(2,5) ]; // a [5,4,3,2,1] // start 0 1 2 - - // end, for... - - - - - // chunks[0] 0 - - - - - // chunks[1] 1 2 - - - // chunks[2] 1 2 3 - - // chunks[3] 1 2 3 4 5 chunks; // [ [], [], [3], [3,2,1] ] a; // [5,4,3,2,1] 

Aslında, olan bu değil, ama bunun hakkında düşünmek daha kolay. MDN'ye göre, gerçekte olan budur:

 // a [5,4,3,2,1] // start 0 1 2 - - - // end, for... - - - - - - // chunks[0] 0 - - - - - // chunks[1] 0 1 2 - - - // chunks[2] 0 1(2)3 - - // chunks[3] 0 1(2 3 4)5 

end belirtilen dizin basitçe dilimden hariç tutulur. Parantez içindeki indeksler neyin dilimlendiğini gösterir. Her durumda, davranış sezgisel değildir ve “birbiri ardına” hata payına neden olduğu gerçeğinden kaynaklanmaktadır, bu nedenle sarıcı işlevinin .splice() davranışının .splice() işlevinden daha fazlasını .splice() .splice() :

 function ez_slice(array, start = 0, n = null){ if(!Array.isArray(array) || !is_number(start)) return null; if(is_number(n)) return array.slice(start, start + n); if(n === null) return array.slice(start); return null; } ez_slice([5,4,3,2,1], 2, 1) // [3] ez_slice([5,4,3,2,1], 2) // [3,2,1]  function is_nan(num){ return typeof num === "number"  num !== num; } function is_number(num){ return !is_nan(num)  typeof num === "number"  isFinite(num); } 

Sarıcı işlevinin çok güçlü türler için olduğunu ve bir şey devre dışı bırakıldığında null döndürdüğünü unutmayın. Bu, "3" türünde bir dize içerir. Programcının türlerinde çalışkan olması için kalır. Bu iyi programlama uygulamasına katkıda bulunmalıdır.

is_array() ilgili güncelleme

Bu, bu (şimdi silinmiş) parça için geçerlidir:

 function is_array(array){ return array !== null  typeof array === "object"  typeof array.length !== "undefined"  array.__proto__ === Array.prototype; } 

Dolayısıyla, bir dizinin gerçekten bir dizi olup olmadığını belirlemek için yerleşik bir yöntem var ve bu ECMAScript 5 (Aralık 2009) 'da tanıtılan Array.isArray() ). Я нашел это, глядя на вопрос, есть ли вопрос о том, чтобы сообщать массивы с объектов, чтобы увидеть, было ли лучшее решение, чем мое, или добавить мое, если их не было. Итак, если вы используете версию JavaScript, которая раньше ECMA 5, там ваш полипол. Тем не менее, я настоятельно рекомендую не использовать is_array() , так как продолжение поддержки старых версий JavaScript означает продолжение поддержки старых браузеров, которые их реализуют, что означает поощрение использования небезопасного программного обеспечения и помещение пользователей под угрозу для вредоносного ПО. Поэтому, пожалуйста, используйте Array.isArray() . Используйте let и const . Используйте новые функции, которые добавляются в язык. Не используйте префиксы поставщиков. Удалите это полисплощадку IE с вашего сайта. Удалите этот XHTML <!CDATA[[... crap, тоже - мы переместились в HTML5 еще в 2014 году.). Чем раньше все откажутся от поддержки этих старых/эзотерических браузеров, тем скорее поставщики браузеров будут действительно следовать веб-стандарту и охватывают новые технологии, и чем скорее мы сможем перейти к более безопасной сети.

164
ответ дан Braden Best 18 сент. '12 в 3:56 2012-09-18 03:56

Старый вопрос, современный ответ. Используя деструктурирование объектов, ECMAScript 6 , это так же просто, как:

 const { a, ...rest } = { a: 1, b: 2, c: 3 };