假设我创建了一个对象,如下所示。
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
怎样才能删除属性regex
,最终得到如下的新myObject
?
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI"
};
像这样。
delete myObject.regex;
// or,
delete myObject['regex'];
// or,
var prop = "regex";
delete myObject[prop];
演示
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
delete myObject.regex;
console.log(myObject);
对于任何有兴趣阅读更多相关内容的人来说,Stack Overflow用户kangax在他们的博客上写了一篇关于delete
语句的令人难以置信的深度博文,了解删除。强烈推荐。
2018-07-21更新:长期以来,我对这个答案感到很尴尬,所以我认为现在是时候把它润色一下了。只是做了一点评论、澄清和格式化,以帮助加快阅读这个答案中不必要的冗长和曲折的部分。
obj // {"foo": "bar"}
delete obj["foo"]
obj // {}
obj["foo"] // undefined
不要从一个数组中删除'。使用
Array.prototype.splice`代替。
arr // [1,2,3,4,5]
arr.splice(3,1); // 4
arr // [1,2,3,5]
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]
,等等)。
说实话,除了设置为 "空 "而不是 "未定义 "外--这很奇怪--这种行为应该不会令人惊讶,因为 "删除 "是一个单数运算符,就像 "typeof "一样,是硬性规定的语言,不应该关心它所使用的对象的类型,而 "Array "是 "Object "的一个子类,其方法专门为处理数组而设计。因此,`delete'没有很好的理由为重移数组而设计一个特殊的案例,因为这只会让事情变得更慢,而没有必要的工作。现在回想起来,我的期望是不现实的。
当然,这**让我吃惊。因为我写这个是为了证明我对"null garbage"的讨伐。
忽略了 "null "所固有的危险和问题,以及所浪费的空间,如果数组需要精确,这就会有问题。 这是摆脱 "null "的一个糟糕的理由--"null "只有在使用不当的情况下才是危险的,它与 "精确 "没有任何关系。你不应该从数组中 "删除 "的真正原因是,把充满垃圾和混乱的数据结构留在身边是很草率和容易产生错误的。 下面是一个设计好的场景,非常啰嗦,所以如果你想的话,可以跳到**解决方案这一节。我留下这一节的唯一原因是,我认为有些人可能认为这很有趣,而我不想成为那个发布了一个 "有趣 "的答案之后又把所有 "有趣 "的东西都删除的人。 ...这很愚蠢,我知道。
矫揉造作、罗嗦的PDP-11方案
例如,假设你正在创建一个webapp,使用JSON-序列化来存储一个用于'标签的数组在一个字符串中(在这种情况下,
localStorage
)。我们还可以说,代码使用数组成员的数字索引,在绘制屏幕时对其进行命名。为什么你要这样做,而不是把"标题"也存储起来?因为......。原因。 好吧,我们就说你是应这个用户的要求来节省内存的,这个用户使用的是1960年代的PDP-11微型计算机,运行的是UNIX系统,他自己写了一个基于Elinks的、符合JavaScript的、适合行式打印机的浏览器,因为X11是不可能的。 撇开越来越愚蠢的边缘情况不谈,在上述数组上使用delete
会导致null
污染数组,并可能在以后的应用程序中造成错误。如果你检查null
,它会直接跳过这些数字,导致标签被渲染成[1] [2] [4] [5] ...
。 if (array[index] == null) 继续。 否则 title = (index + 1).toString(); / 0 -> "1"
- 1 -> "2"
- 2 -> (无)。
- 3 -> "4" / 是的,这绝对不是你想要的结果。 现在,你可以保留第二个迭代器,比如
j
,只在从数组中读取有效值时才递增。但这并不能完全解决 "空 "的问题,而且你还得讨好那个巨魔PDP-11用户。唉,他的电脑就是*没有足够的内存来容纳最后一个整数(不要问他是如何处理可变宽度的数组的...)。 于是,他愤怒地给你发了一封电子邮件。 嘿,你的网络应用程序弄坏了我的浏览器!?在你的愚蠢代码使我的浏览器发生故障后,我检查了我的localStorage数据库,这是我发现的。"标签:['Hello World', 'foo bar baz', null, null, null, null, null, null, ...]"。 在清除了我宝贵的数据后,它又发生了分离故障,我做了一个回溯,我发现了什么?我发现了什么!?你使用了太多的变量!? var i = index; var j = 1; Grrr,我现在很生气。 -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先生满意了。万岁!(虽然我还是会告诉他...)</sub>。
我觉得有必要指出这两个名字相似的函数之间的区别,因为它们都非常有用。
.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]
.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;
}
事实证明, 确实有一个内置的方法来判断一个数组是否真的是一个数组, 那就是ECMAScript 5 (2009年12月)中引入的Array.isArray()
.我在寻找是否有关于区分数组和对象的问题时发现了这个问题,想看看是否有比我更好的解决方案,如果没有的话,也可以添加我的。所以,如果你使用的是早于ECMA 5的JavaScript版本,你的polyfill就来了。然而,我强烈建议不要使用我的is_array()
函数,因为继续支持旧版本的JavaScript意味着继续支持实现它们的旧浏览器,这意味着鼓励使用不安全的软件,使用户面临恶意软件的风险。所以,请使用Array.isArray()
。使用let
和const
。使用被添加到语言中的新功能。不要使用供应商的前缀。删除你网站上的IE polyfill垃圾。也删除XHTML的<!CDATA[[...]
垃圾--我们早在2014年就搬到了HTML5。大家越早撤销对那些老旧/深奥的浏览器的支持,浏览器供应商就会越早真正遵循网络标准并接受新技术,我们就能越早进入一个更安全的网络。