Como remover uma propriedade de um objeto javascript?

Digamos que eu crie um objeto como este:

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

Qual é a melhor maneira de remover a propriedade regex , para acabar com um novo myObject como este:

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI" }; 
5276
16 окт. set johnstok 16 de outubro . 2008-10-16 13:57 '08 às 13:57 2008-10-16 13:57
@ 37 respostas
  • 1
  • 2

Aqui está:

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

Demonstração

kangax escreveu uma postagem incrivelmente detalhada sobre a declaração delete em seu blog, Understanding Deletion .  Altamente recomendado. 

7292
16 окт. a resposta é dada em 16 de outubro. 2008-10-16 13:58 '08 às 1:58 pm 2008-10-16 13:58

delete operador inesperadamente desacelera!

Olhe para o benchmark .

Excluir é a única maneira segura de remover as propriedades de um objeto sem resíduos, mas funciona ~ 100 vezes mais lentamente em comparação com o object[key] = undefined configuração "alternativo" object[key] = undefined .

Essa alternativa não é a resposta certa para essa pergunta! Mas, se você usá-lo com cuidado, você pode acelerar significativamente alguns algoritmos. Se você usar delete in loops e tiver problemas de desempenho, leia a explicação detalhada.

Quando delete deve ser usado e quando o valor especificado é undefined ?

Um objeto pode ser considerado como um conjunto de pares de valores-chave. O que eu chamo de "valor" é uma primitiva ou referência a outro objeto associado a essa "chave".

Use delete quando você passar um objeto de resultado para um código no qual você não tem controle (ou quando você não está confiante em sua equipe ou em você mesmo).

Remove a chave do cartão de hash .

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

Se você não tiver certeza sobre o desempenho, use a opção undefined . Isso pode afetar seriamente seu código.

A chave permanece em seu lugar no hashmap , apenas o valor é substituído por undefined . Entenda que o ciclo for..in ainda passará por essa chave.

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

Usando esse método, nem todos os métodos para determinar a propriedade de existência funcionarão conforme o esperado.

No entanto, este código:

object.field === undefined

irá se comportar de maneira equivalente para ambos os métodos.

Testes

Resumindo, existem diferenças nas formas de determinar a existência de uma propriedade e para ... for..in loop for..in .

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. *'); 

Cuidado com vazamentos de memória!

Embora obj[prop] = undefined mais rápido que delete obj[prop] , outra consideração importante é que obj[prop] = undefined pode nem sempre ser relevante. delete obj[prop] remove prop do obj e apaga-o da memória, enquanto obj[prop] = undefined simplesmente define o valor prop para undefined que deixa prop ainda na memória. Portanto, em situações em que há muitas chaves criadas e excluídas, o uso de obj[prop] = undefined pode levar a uma consistência de memória cara (fazendo com que a página congele) e potencialmente a um erro de falta de memória. Examine o código a seguir.

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

No código acima, apenas nodeRecords[i][lastTime] = undefined; resultará em um vazamento massivo de memória devido a cada quadro de animação. Cada frame, todos os elementos do 65536 DOM ocuparão outros 65.536 slots individuais, mas os slots anteriores 65.536 serão definidos apenas como undefined, o que os deixa pendurados na memória. Vá em frente, tente executar o código acima no console e veja por si mesmo. Após um erro de memória forçada, tente executá-lo novamente, com exceção da próxima versão do código, que usa o operador delete .

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

Como pode ser visto no snippet de código acima, existem alguns usos adequados raros para o operador delete . No entanto, não se preocupe muito com esse problema. Isso se tornará um problema apenas com objetos de vida longa, que constantemente adicionam novas chaves a eles. Em qualquer outro caso (isto é quase todo caso em programação real), é mais aconselhável usar obj[prop] = undefined . O principal objetivo desta seção é simplesmente chamar a atenção para o fato de que, em casos raros, isso se torna um problema em seu código. Assim, você pode entender mais facilmente o problema e, portanto, não perder tempo analisando seu código para encontrar e entender esse problema.

Nem sempre definido como undefined

Um aspecto do Javascript que é importante considerar é o polimorfismo. Polimorfismo é a atribuição de variáveis ​​/ slots idênticas em objetos de diferentes tipos, como mostrado abaixo.

 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 

No entanto, existem dois problemas principais que não podem ser eliminados ao usar matrizes polimórficas:

  1. Eles são lentos e ineficazes. Ao acessar um índice específico, em vez de simplesmente obter um tipo global para uma matriz, o navegador deve receber um tipo baseado em um índice, no qual cada índice armazena metadados adicionais de seu tipo.
  2. Depois de polimórfico, sempre polimórfico. Quando uma matriz é feita polimórfica, o polimorfismo não pode ser cancelado nos navegadores Webkit. Assim, mesmo se você restaurar um array polimórfico como não-polimórfico, ele ainda será armazenado pelo navegador como um array polimórfico.

Você pode comparar o polimorfismo da dependência de drogas. À primeira vista, parece incrivelmente lucrativo: um código bonito e bastante fofo. O codificador então entra em sua matriz em uma droga polimórfica. Instantaneamente, uma matriz polimórfica se torna menos eficaz, e nunca pode se tornar tão eficaz quanto antes, já que é anestesiada. A fim de relacionar tal circunstância à vida real, alguém da cocaína pode nem mesmo ser capaz de operar uma maçaneta de porta simples, e muito menos ser capaz de calcular números PI. Da mesma forma, uma matriz em uma preparação de polimorfismo não pode ser tão eficaz quanto uma matriz monomórfica.

Mas como a analogia da droga se refere à operação de delete ? A resposta contém a última linha de código no fragmento acima. Então deixe-o ser revisado, desta vez com uma torção.

 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 

Preste atenção. bar[1] = "" não causa polimorfismo, enquanto bar[1] = undefined faz. Portanto, é sempre necessário, quando possível, usar o tipo apropriado para seus objetos para não causar acidentalmente polimorfismo. Uma dessas pessoas pode usar a seguinte lista como um link geral para obtê-las. No entanto, por favor, não use as idéias abaixo. Em vez disso, use o que funciona bem para o seu código.

  • Ao usar uma matriz / variável inserida em uma primitiva booleana, use o valor false ou undefined como um valor vazio. Embora evitar polimorfismo desnecessário seja bom, reescrever todo o código para desativá-lo explicitamente provavelmente resultará em desempenho insatisfatório. Use julgamento sadio!
  • Ao usar uma matriz / variável inserida em uma primitiva numérica, use 0 como o valor vazio. Observe que há dois tipos de números dentro: inteiros rápidos (de 2147483647 a -2147483648 inclusive) e pontos de vírgula flutuante duplos lentos (qualquer coisa diferente de NaN e Infinity ). Quando um inteiro cai em um duplo, ele não pode ser classificado como um inteiro.
  • Ao usar uma matriz / variável inserida em uma primitiva de seqüência de caracteres, use "" como o valor vazio.
  • Ao usar o símbolo, espere, por que você está usando o símbolo?!?! Bad juju caracteres para o desempenho. Todos os caracteres programados para uso podem ser reprogramados para não usar caracteres, o que resulta em um código mais rápido e livre de código. Os símbolos são realmente apenas um meta-açúcar ineficaz.
  • Ao usar qualquer outra coisa, use null .

No entanto, tenha cuidado! Não comece a fazer isso com todo o código existente, pois é provável que ele quebre o código existente e / ou apresente erros estranhos. Em vez disso, essa prática eficaz deve ser implementada desde o início e, ao converter o código existente, recomenda-se duplicar, triplicar, quadruplicar verificações de todas as linhas relacionadas a isso, pois uma tentativa de atualizar o código antigo para essa nova prática pode ser tão arriscada quanto útil. .

770
12 февр. Responder Dan 12 fev 2014-02-12 20:48 '14 às 20:48 2014-02-12 20:48

215
16 окт. a resposta é dada pelo redsquare 16 de outubro. 2008-10-16 14:03 '08 às 2:03 pm 2008-10-16 14:03

Atualização 2018-07-21: Por um longo tempo eu me senti envergonhado com essa resposta, então eu acho que toquei um pouco. Apenas um pequeno comentário, esclarecimento e formatação para acelerar a leitura de partes longas e confusas desnecessárias desta resposta.


VERSÃO CURTA

A resposta real à pergunta

Como outros já disseram, você pode usar delete .

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

Equivalente maciço

Não delete da matriz. Array.prototype.splice deste uso Array.prototype.splice .

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

VERSÃO LONGA

JavaScript é uma linguagem OOP, então tudo é um objeto, incluindo matrizes. Assim, considero necessário assinalar um aviso específico.

Em arrays, em contraste com objetos antigos simples, o uso de delete deixa o lixo na forma de null , criando um "buraco" na matriz.

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

Como você pode ver, a delete nem sempre funciona como esperado. O valor é sobrescrito, mas a memória não é redistribuída. Em outras palavras, array[4] não se move para array[3] . Ao contrário de Array.prototype.unshift , que insere um elemento no início de um array e desloca tudo para cima ( array[0] se torna array[1] , etc.),

Honestamente, além de definir null e não undefined que é completamente estranho - este comportamento não deve ser surpreendente, porque delete é um operador unário, como typeof , que é rigidamente distorcido na linguagem e não deve se importar com o tipo de objeto usado, Array é uma subclasse de Object com métodos projetados especificamente para trabalhar com arrays. Portanto, não há motivo para que o delete tenha um caso especial preparado para re-deslocar um array, pois isso simplesmente retardará o trabalho com trabalho desnecessário. Olhando para trás, minhas expectativas não eram realistas.

Claro que me surpreendeu. Porque eu escrevi para justificar minha cruzada contra "lixo zero":

Ignorando os perigos e problemas inerentes ao espaço null e desperdiçado, isso pode ser problemático se o array precisar ser exato.

Que é uma desculpa terrível para se livrar de null s - null é perigoso apenas se usado incorretamente e não tem nada a ver com "precisão". A verdadeira razão pela qual você não deve delete de uma matriz é porque deixar as estruturas de dados sujas e cheias de lixo está confuso e propenso a erros.

Abaixo está um script artificial que fica bastante longo, então você pode ir para a seção "Solução" se quiser. A única razão pela qual eu deixo essa seção é que eu acho que algumas pessoas provavelmente acham engraçado, e eu não quero ser o “cara” que envia a resposta “engraçada” e então a apaga. tudo "engraçado",

... Isso é estúpido, eu sei.

O cenário planejado e de longo prazo PDP-11

Por exemplo, suponha que você crie um webapp que use a serialização JSON para armazenar o array usado para as guias em uma string ( localStorage neste caso). Deixe-os também dizer que o código usa os índices numéricos dos elementos da matriz para "nomenclá-los" ao desenhar na tela. Por que você está fazendo isso e não apenas mantendo o "título"? Porque ... razões.

Bem, deixe-me dizer que você está tentando economizar memória a pedido deste usuário que executa o minicomputador PDP-11 desde 1960, executando o UNIX, e escreveu sua própria interface compatível com JavaScript com suporte ao navegador JavaScript, porque o X11 não é fora de questão.

Um script cada vez mais estúpido do script marginal usando delete na matriz especificada null poluição da matriz e provavelmente levará a erros no aplicativo posteriormente. E se você marcar null , ele irá automaticamente pular números, com o resultado de que as abas exibidas se parecem com [1] [2] [4] [5]...

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

Sim, definitivamente não é isso que você queria.

Agora você pode salvar o segundo iterador, por exemplo, j , para incrementar somente quando os valores reais forem lidos da matriz. Mas isso definitivamente não resolve o problema null , e você ainda gosta desse usuário Troll PDP-11. Infelizmente, o computador dele simplesmente não tem memória suficiente para armazenar esse último número inteiro (não pergunte como ele consegue lidar com uma matriz de largura variável ...) .

Então ele envia uma carta com raiva:

 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 

Agora você está no seu final. Esse cara reclamava constantemente do seu aplicativo, e você quer dizer a ele para calar a boca e ir ao melhor computador.

Solução: Array.prototype.splice

Felizmente, as matrizes têm um método especial para remover índices e realocar memória: Array.prototype.splice() . Você poderia escrever algo assim:

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

E assim, você está satisfeito com o Sr. PDP-11. Viva! (Eu ainda diria a ele embora ...)

Array.prototype.splice vs Array.prototype.slice

Eu acho importante notar a diferença entre essas duas funções de nome similar, já que ambas são muito úteis.

Array.prototype.splice (start, n)

.splice() muta uma matriz e retorna índices remotos. O array é cortado a partir do índice, start e n elementos são cortados. Se n não for especificado, toda a matriz após start 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 (início, fim)

.slice() é não-destrutivo e retorna uma nova matriz contendo os índices especificados do start ao end . Se end especificado, o comportamento será o mesmo que .splice() ( end = array.length ). O comportamento é um pouco complicado, porque, por alguma razão, os índices end começam em 1 em vez de 0. Não sei por que isso acontece, mas é. Além disso, se end <= start , o resultado é um array vazio.

 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] 

Na verdade, isso não é o que acontece, mas é mais fácil pensar sobre isso. De acordo com o MDN, isso é o que realmente acontece:

 // 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 

O índice especificado por end é simplesmente excluído da fatia. Os índices entre parênteses indicam o que está sendo fatiado. Em qualquer caso, o comportamento não é intuitivo e é devido ao fato de que faz com que seu quinhão de erros "um após o outro", então você pode achar útil fazer a função wrapper mais do que .splice() comportamento de .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); } 

Observe que a função de invólucro é para tipos muito fortes e retorna null se algo estiver desabilitado. Isso inclui uma string do tipo "3" . Resta ao programador ser diligente em seus tipos. Isso deve contribuir para uma boa prática de programação.

Atualização sobre is_array()

Isso se aplica a esse fragmento (agora excluído):

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

Итак, как оказалось, на самом деле есть встроенный способ определить, действительно ли массив является массивом, и это Array.isArray() , введенный в ECMAScript 5 (декабрь 2009 г.). Я нашел это, глядя на вопрос, есть ли вопрос о том, чтобы сообщать массивы с объектов, чтобы увидеть, было ли лучшее решение, чем мое, или добавить мое, если их не было. Итак, если вы используете версию 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 };