4 回答
TA贡献1775条经验 获得超8个赞
var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
delete myObject.regex;
console.log ( myObject.regex); // logs: undefined
TA贡献2041条经验 获得超4个赞
短版
这个问题的实际答案
正如其他人所说,你可以使用delete。
obj // {"foo": "bar"}
delete obj["foo"]
obj // {}
obj["foo"] // undefined
数组等价
不要delete从阵列。请Array.prototype.splice改用。
arr // [1,2,3,4,5]
arr.splice(3,1); // 4
arr // [1,2,3,5]
长版
JavaScript是一种OOP语言,所以一切都是对象,包括数组。因此,我认为有必要指出一个特别的警告。
在数组中,与普通的旧对象不同,使用delete垃圾形式的叶子null,在数组中创建一个“洞”。
var array = [1, 2, 3, 4];
delete array[2];
/* Expected result --> [1, 2, 4]
* Actual result --> [1, 2, null, 4]
*/
正如您所看到的,delete并不总是像人们期望的那样工作。该值被覆盖,但内存未重新分配。也就是说,array[4]没有重新安置array[3]。与之形成对比的是Array.prototype.unshift,它在数组的开头插入一个元素并将所有内容都移位(array[0]变为array[1]等)
老实说,除了设置null而不是undefined,可呈现为合法怪异-这种行为不应该是不足为奇的,因为delete是一元运算符,如typeof,就是煮到语言,不应该在乎类型的对象正在被使用,而是使用专门用于处理数组的方法Array的子类。所以没有充分的理由让一个特殊的盒子用于重新移动阵列,因为这会减少不必要的工作。回想起来,我的期望是不现实的。Objectdelete
当然,这也让我感到吃惊。因为我写这篇文章是为了证明我对“空垃圾”的讨伐:
忽略固有的危险和问题null,以及浪费的空间,如果阵列需要精确,这可能会有问题。
这是摆脱了可怕的理由nullS-- null只危险的,如果使用不当,它没有任何与“精确”。你不应该delete从数组中获得的真正原因是,留下垃圾填充和混乱的数据结构是邋and和容易出错的。
接下来是一个设计得非常冗长的场景,所以如果你愿意,可以跳到“解决方案”这一部分。我离开这一部分的唯一原因是,我认为有些人可能认为这很有趣,而且我不想成为那个发布“有趣”答案然后从中删除所有“搞笑”的“那个人”。 。
......我知道,这很愚蠢。
设计和冗长的PDP-11场景
例如,假设您正在创建一个webapp,它使用JSON序列化来存储用于字符串中“tabs”的数组(在本例中localStorage)。我们还要说代码在绘制到屏幕时使用数组成员的数字索引来“标题”它们。你为什么这样做而不仅仅是存储“标题”?因为...... 原因。
好的,我们只是说你正在努力节省内存,应运行这台运行一台1960年代运行UNIX的PDP-11小型机的用户,并编写了自己的基于Elinks,符合JavaScript标准的线路打印机友好型浏览器因为X11是不可能的。
除了越来越愚蠢的边缘情况之外,delete在所述数组上使用将导致null污染数组,并可能在以后导致应用程序中的错误。如果你检查null,它会直接跳过数字,导致标签被渲染出来[1] [2] [4] [5] ...。
if (array[index] == null)
continue;
else
title = (index + 1).toString();
/* 0 -> "1"
* 1 -> "2"
* 2 -> (nothing)
* 3 -> "4"
*/
是的,这绝对不是你想要的。
现在,您可以保留第二个迭代器,例如j,仅在从数组中读取有效值时才递增。但这并不能完全解决null问题,你仍然需要取悦那个troll PDP-11用户。唉,他的计算机没有足够的内存来容纳最后一个整数(不要问他是如何设法处理可变宽度数组的......)。
所以,他给你发了一封愤怒的电子邮件:
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
现在,你的智慧结束了。这家伙一直抱怨你的应用程序不停,你想告诉他闭嘴,去买一台更好的电脑。
解决方案: Array.prototype.splice
幸运的是,数组确实有一种删除索引和重新分配内存的专门方法:Array.prototype.splice()。你可以写这样的东西:
Array.prototype.remove = function(index){
this.splice(index,1);
}
...
array = [1, 2, 3, 4];
array.remove(2);
// Result -> [1, 2, 4]
就这样,你很高兴PDP-11先生。万岁!(我还是告诉他,不过......)
Array.prototype.splice vs Array.prototype.slice
我觉得指出这两个同名的函数之间的区别非常重要,因为它们都非常有用。
Array.prototype.splice(start,n)
.splice()改变数组,并返回删除的索引。从索引开始切割数组start,并n切出元素。如果未指定n,则将整个数组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(开始,结束)
.slice()是非破坏性的,并返回从含有指示索引的新的数组start,以end。如果end未指定,则行为与.splice()(end = array.length)相同。这个行为有点棘手,因为由于某种原因,end索引从1而不是0.我不知道为什么会这样做,但事实就是如此。另外,如果end <= start,结果是一个空数组。
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]
这实际上不是正在发生的事情,但更容易想到这种方式。根据MDN,这是实际发生的事情:
// 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只是从切片中排除。带括号的索引表示切片的内容。无论哪种方式,行为都不直观,并且它必然导致其公平分享一个一个错误,因此您可能会发现使包装函数更接近地模拟以下行为是有用的.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]
/* Fun fact: isNaN is unreliable.
* [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(isNaN)
* [NaN, {}, undefined, "Hi"]
*
* What we want is...
*
* [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(is_nan)
* [NaN]
*/
function is_nan(num){
return typeof num === "number"
&& num !== num;
}
function is_number(num){
return !is_nan(num)
&& typeof num === "number"
&& isFinite(num);
}
请注意,包装函数的设计对类型非常严格,null如果有任何关闭则会返回。这包括输入一个字符串"3"。程序员需要勤勉地研究他的类型。这是为了鼓励良好的编程实践。
有关的更新 is_array()
这是关于这个(现在删除)的片段:
function is_array(array){
return array !== null
&& typeof array === "object"
&& typeof array.length !== "undefined"
&& array.__proto__ === Array.prototype;
}
事实证明,实际上有一种内置的方法来判断一个数组是否真的是一个数组,这就是Array.isArray()在ECMAScript 5(2009年12月)中引入的。我找到了这个,同时查看是否有一个问题询问是否从对象告诉数组,看看是否有比我更好的解决方案,或者如果没有,则添加我的。因此,如果您使用的是早于ECMA 5的JavaScript版本,那么就是您的polyfill。但是,我强烈建议不要使用我的is_array()功能,因为继续支持旧版本的JavaScript意味着继续支持实现它们的旧浏览器,这意味着鼓励使用不安全的软件并使用户面临恶意软件的风险。所以,请使用Array.isArray()。使用let和const。使用添加到该语言的新功能。不要使用供应商前缀。从您的网站删除 IE polyfill废话。删除那个XHTML <!CDATA[[...废话 - 我们在2014年转移到HTML5。每个人都越早撤回对那些旧/深奥浏览器的支持,浏览器供应商越早实际遵循Web标准并采用新技术,我们越早能够转向更安全的网络。
添加回答
举报