在Javascript中从数组中删除空元素

1601

如何从JavaScript数组中删除空元素?

有没有简单直接的方法,还是必须手动循环并逐个删除?


27
如果你的问题能够明确指出“空元素”指的是什么,那将会很有帮助,因为这里的大部分答案(在我看来)错误地将其解释为“假值”元素。注意:var a = [,,]var a = [undefined, undefined]之间存在区别。前者是真正的空数组,而后者实际上有两个键,但值为undefined - Alnitak
虽然不是完全的答案,但我认为在数组中尽可能避免使用null/undefined是更好的实践。例如,如果你的null来自于使用map函数映射另一个数组时,对于某些元素返回null,那么在运行map之前尝试使用Array.filter过滤掉这些元素。这样可以使你的代码更易读/自我记录。显然,这并不适用于每种情况,但它可以应用于很多情况。 - Luke Redmore
51个回答

1771

几种简单的方法:

var arr = [1,2,,3,,-3,null,,0,,undefined,4,,4,,5,,6,,,,];

arr.filter(n => n)
// [1, 2, 3, -3, 4, 4, 5, 6]

arr.filter(Number) 
// [1, 2, 3, -3, 4, 4, 5, 6]

arr.filter(Boolean) 
// [1, 2, 3, -3, 4, 4, 5, 6]

or - (仅适用于类型为"text"的单个数组项)

['','1','2',3,,'4',,undefined,,,'5'].join('').split(''); 
// output:  ["1","2","3","4","5"]

或 - 经典方式:简单迭代

var arr = [1,2,null, undefined,3,,3,,,0,,,[],,{},,5,,6,,,,],
    len = arr.length, i;

for(i = 0; i < len; i++ )
    arr[i] && arr.push(arr[i]);  // copy non-empty values to the end of the array

arr.splice(0 , len);  // cut the array and leave only the non-empty values
// [1,2,3,3,[],Object{},5,6]

jQuery:

var arr = [1,2,,3,,3,,,0,,,4,,4,,5,,6,,,,];
    
arr = $.grep(arr, n => n == 0 || n);
// [1, 2, 3, 3, 0, 4, 4, 5, 6]

37
滤镜的最早IE支持是IE9标准模式。 - yincrash
21
纯 JavaScript 的话应该是 arr = arr.filter(function(n){return n; }); - ilumin
28
只有当字符串是单个字符时,foo.join("").split("") 才有效。 - Atav32
16
你的纯 JavaScript 代码有一个 bug。如果数组中的值为 "0",该值将被过滤掉,因为 "0" 是 falsy。你想要的是:arr.filter(function (n) { return (n !== undefined && n !== null); }); - John Kurlak
13
ES6可以更加简单地实现这个功能 arr.filter(e=>e),并且可以通过map、reduce等方法进行链式操作。 - Sheepy
显示剩余30条评论

1474

编辑: 这个问题在将近9年前得到了回答,当时Array.prototype中没有很多有用的内置方法。

现在,我会建议你使用filter方法。

请注意,该方法将返回一个新数组,其中包含通过你提供给它的回调函数的标准的元素。

例如,如果你想要移除null或者undefined值:

var array = [0, 1, null, 2, "", 3, undefined, 3,,,,,, 4,, 4,, 5,, 6,,,,];

var filtered = array.filter(function (el) {
  return el != null;
});

console.log(filtered);

这将取决于您认为什么是“空的”,例如,如果您正在处理字符串,则上述函数不会删除空字符串元素。

我经常看到使用的一种典型模式是删除假值元素,包括空字符串""0NaNnullundefinedfalse

您可以将Boolean构造函数传递给filter方法,或在筛选条件函数中返回相同的元素,例如:

var filtered = array.filter(Boolean);

或者
var filtered = array.filter(function(el) { return el; });

这两种方法都是可行的,因为在第一种情况下,filter方法作为函数调用Boolean构造函数,将值转换为布尔值;在第二种情况下,filter方法内部将回调函数的返回值隐式转换为布尔值。

如果您正在使用稀疏数组,并且想要摆脱"空洞",您可以使用filter方法传递一个返回true的回调函数,例如:

var sparseArray = [0, , , 1, , , , , 2, , , , 3],
    cleanArray = sparseArray.filter(function () { return true });

console.log(cleanArray); // [ 0, 1, 2, 3 ]

旧回答:不要这样做!

我使用这种方法,扩展本地的Array原型:

Array.prototype.clean = function(deleteValue) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] == deleteValue) {         
      this.splice(i, 1);
      i--;
    }
  }
  return this;
};

test = new Array("", "One", "Two", "", "Three", "", "Four").clean("");
test2 = [1, 2,, 3,, 3,,,,,, 4,, 4,, 5,, 6,,,,];
test2.clean(undefined);

或者您可以将现有的元素简单地推入其他数组:

// Will remove all falsy values: undefined, null, 0, false, NaN and "" (empty string)
function cleanArray(actual) {
  var newArray = new Array();
  for (var i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i]);
    }
  }
  return newArray;
}

cleanArray([1, 2,, 3,, 3,,,,,, 4,, 4,, 5,, 6,,,,]);

121
警告:第二个选项将从数组中删除任何被视为“假”的元素,即false、0、null和undefined的值。 即使我可能希望具有值为0的元素存在于这个数组中,但这个数组最终会变成空的:[null,,,0,,0,0,0,false,null,0],而像这个数组:[1,0,1,0,0,1]中具有值为0的元素也会被删除。 - Jason Bunting
5
我明白了,这就是为什么我只谈论第二个选项。至于第一个选项,它的范围非常狭窄,以至于我不敢将其作为数组原型的一部分。请参见此页面上Alnitak的答案,那会更理想些。不过你的方法显然可以允许链接。 - Jason Bunting
2
@AlfaTek - 在除了最新的浏览器之外,#2将拥有最佳性能,因为JS中的数组实际上并不是真正的数组。在旧版浏览器中,splice调用非常昂贵,因为它们必须重新编号所有数组键以关闭间隙。 - Alnitak
1
@David 不,现代代码中你应该使用 Object.defineProperty 安全地 扩展 Array.prototype,使新函数成为一个 _不可枚举的属性_,然后避免在每个循环中使用 .hasOwnProperty 带来的性能损失。 - Alnitak
1
旧答案:不要这样做!为什么不呢?如果你必须原地操作,因为你还想更新对数组的引用呢?那么splice就是这个答案中最有用的部分。我猜更好的答案是避免一开始就放置null值。 - nurettin
显示剩余15条评论

265
如果您需要移除所有空值(包括:"",null,undefined和0):
arr = arr.filter(function(e){return e}); 

删除空值和换行符:

arr = arr.filter(function(e){ return e.replace(/(\r\n|\n|\r)/gm,"")});

例子:

arr = ["hello",0,"",null,undefined,1,100," "]  
arr.filter(function(e){return e});

返回:

["hello", 1, 100, " "]

更新(基于Alnitak的评论)

在某些情况下,您可能希望保留数组中的“0”并删除其他内容(null、undefined和“”),以下是一种方法:

arr.filter(function(e){ return e === 0 || e });

返回:

["hello", 0, 1, 100, " "]

3
测试函数可以更加明确一些:function(e){return !!e} - Koen.
4
请注意,!!e 会包含 NaN(不同于 0),而 e 不会(就像 0)。 - Sheepy
并没有真正回答所提出的问题。 - Alnitak
@Alnitak:这完全取决于你如何定义“空”。我根据你的评论更新了我的答案。谢谢! - lepe
2
使用 var myarr=[1, 2,, 3,, 3,undefined,,"",,0, 4,, 4,, 5,, 6,,,,].filter(Boolean); 可以移除 undefined,"" 和 0。 - Mark Schultheiss
显示剩余3条评论

143

简单来说,只需要一行代码:

[1, false, "", undefined, 2].filter(Boolean); // [1, 2]

或者使用underscorejs.org

_.filter([1, false, "", undefined, 2], Boolean); // [1, 2]
// or even:
_.compact([1, false, "", undefined, 2]); // [1, 2]

1
这真的很酷 - 我有一个新手问题:看起来你正在使用类名作为函数调用 - 这是类型转换吗?我以前没有见过这种情况,也不确定为什么传递 Boolean 作为函数会起作用... - Andrew
9
如果你将 Boolean 视为一个函数,它将返回值的真/假性,即 truefalse。请注意,这不会改变原始值的类型。 - Andreas Louv
9
你没有将 Boolean 作为一个函数来处理;它实际上是一个函数。(除了原生实现之外,它是一个完全普通的函数。)有人需要研究一下 JavaScript 对象模型。 ;) - ELLIOTTCABLE
不知道你在说什么,@null。 - ELLIOTTCABLE
1
如果数组中存在值为0,则两者都将失败。 - Sai Ram
显示剩余2条评论

138

如果你有 Javascript 1.6 或更高版本,你可以使用 Array.filter 函数并使用一个简单的 return true 回调函数,例如:

arr = arr.filter(function() { return true; });

由于.filter自动跳过原始数组中缺失的元素,因此需要注意。

上面链接的MDN页面还包含一个良好的错误检查版本的filter,可用于不支持官方版本的JavaScript解释器。

请注意,这不会删除null条目或具有明确的undefined值的条目,但是OP明确要求“丢失”的条目。


3
正如Alnitak所说的那样,他们有可以在没有js 1.6的情况下使用的代码。 - Sameer Alibhai
不行,似乎只要它不是未定义的,就是真的。 - sqram
3
@katsh 我已经澄清了-上面的代码确实可以删除没有任何值的条目,而这与存在一个键但其赋给定值为undefined的情况在语义上是不同的。(我随后)学到了这一点。 - Alnitak
4
要删除未定义或空值的条目,只需进行小修改... arr = arr.filter(function(v) { return v; }); - Alan CN
6
@AlanCN,你完全没理解我的意思。OP要求删除_missing_条目,而这里大部分回答(不正确地)删除了任何“falsey”条目。 - Alnitak
显示剩余2条评论

114

要删除空洞,请使用

arr.filter(() => true)
arr.flat(0) // New in ES2019

用于删除hole、null和undefined:

arr.filter(x => x != null)

用于删除空值、假值(null、undefined、0、-0、0n、NaN、""、false、document.all)的函数:

arr.filter(x => x)

arr = [, null, (void 0), 0, -0, 0n, NaN, false, '', 42];
console.log(arr.filter(() => true)); // [null, (void 0), 0, -0, 0n, NaN, false, '', 42]
console.log(arr.filter(x => x != null)); // [0, -0, 0n, NaN, false, "", 42]
console.log(arr.filter(x => x)); // [42]

注意:

  • 空洞指的是数组中没有元素的某些索引。
arr = [, ,];
console.log(arr[0], 0 in arr, arr.length); // undefined, false, 2; arr[0] is a hole
arr[42] = 42;
console.log(arr[10], 10 in arr, arr.length); // undefined, false, 43; arr[10] is a hole

arr1 = [1, 2, 3];
arr1[0] = (void 0);
console.log(arr1[0], 0 in arr1); // undefined, true; a[0] is undefined, not a hole

arr2 = [1, 2, 3];
delete arr2[0]; // NEVER do this please
console.log(arr2[0], 0 in arr2, arr2.length); // undefined, false; a[0] is a hole
  • 所有以上的方法都返回给定数组的副本,而不是在原地进行修改。
arr = [1, 3, null, 4];
filtered = arr.filter(x => x != null);
console.log(filtered); // [1, 3, 4]
console.log(arr); // [1, 3, null, 4]; not modified

4
请问您需要的是:“这应该在答案中排得很靠前。您能否详细解释一下'hole'的含义?” - samayo
2
@samayo 的意思是未填充的数组项,例如 [, ,] - Jimmy Obonyo Abor
1
通过使用 arr.filter(x => x),JS 将检查 x 是否为真或假,即 if (x),因此只有真值将被分配到新列表中。 - ckybonist

60

干净的做法。

var arr = [0,1,2,"Thomas","false",false,true,null,3,4,undefined,5,"end"];
arr = arr.filter(Boolean);
// [1, 2, "Thomas", "false", true, 3, 4, 5, "end"]

7
空元素是未定义的(undefined),这基本上会删除所有假值(falsy values)。 - pimvdb

53

实际上,您可以使用ES6+方法,假设数组如下:

const arr = [1,2,3,undefined,4,5,6,undefined,7,8,undefined,undefined,0,9];

答案可能是以下两种方式之一:

  • First way:

    const clearArray = arr.filter(i => i); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
    
  • Second way:

    const clearArray = arr.filter(Boolean); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
    

2022年10月14日更新:

那两个答案即使在给定的示例中也不是完全正确的,是的,它们能够工作,但请注意给定数组中的数字0,通过这两种方法,数字零都被删除了,这显然与使用布尔强制检查项目有关。

一个完全正确的方法是检查并删除nullish值:

const notNil = (i) => !(typeof i === 'undefined' || i === null);

const clearArray = arr.filter(i => isNil(i));

const arr = [1,2,3,undefined,4,5,6,undefined,7,8,undefined,undefined,0,9];
const notNil = (i) => !(typeof i === 'undefined' || i === null);

console.log("Not nil: ", arr.filter(notNil));


arr.filter(i) => typeof i === 'number'; 会产生相同的结果吗? - iiminov
亲爱的 @iiminov,为什么您预设数组项是“数字”?它们可以是任何东西,主要目的是清除所有“Nil”事物。 - AmerllicA
抱歉 @AmerllicA,我没有做任何假设。我只想从数组中获取数字。所以根据示例数组,我应该能够直接按类型进行过滤以获得相同的结果。当然,如果我想保留除 null 和 undefined 之外的所有内容,那么我会相应地进行过滤。 - iiminov

43

ES6:

let newArr = arr.filter(e => e);

42

简单的 ES6

['a','b','',,,'w','b'].filter(v => v);

2
这个不起作用:[1,'two',null,undefined,,NaN,false,true,0] .filter(v => v) - zipper
[1, 'two', null, undefined, , NaN, false, true, 0].filter(v => v!=null) 保留 NaN 和 false。 - Julian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接