如何使用Array.prototype.filter过滤对象?

时间:2016-03-26 06:57:01

标签: javascript arrays ecmascript-6 ecmascript-7 ecmascript-next

给出

var arr = [1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]]

我们可以使用arr构造函数

过滤数组Number中的数字项
var res = arr.filter(Number); // [1, 2, true, 4, 6, 7, 9, Array[1]]
结果数组中

true[10]吗?如果我们在false

替换true arr
var arr = [1,2,false,4,{"abc":123},6,7,{"def":456},9,[10]] 
var res = arr.filter(Number) // [1, 2, 4, 6, 7, 9, Array[1]]

使用Array.isArray

var res = arr.filter(Array.isArray) // [Array[1]]

String

var res = arr.filter(String) // [1, 2, true, 4, Object, 6, 7, Object, 9, Array[1]]

如果我们要过滤arr中的对象项目,请在索引47处尝试

var res = arr.filter(Object) // [1, 2, true, 4, Object, 6, 7, Object, 9, Array[1]]

虽然我们更愿意简单地调用arr.filter(Object),但我们可以传递函数调用;尝试Object的不同属性,以便我们最终可以找到一个属性或方法,我们可以将其用作函数或构造函数作为模式传递给arr.filter(/* method, constructor, other approach */)以返回与对象匹配的过滤结果,甚至输入数组中对象的属性名称或值。

我们通过检查数组中的项目constructor是否name等于"Object"

来无辜地开始
 var res = arr.filter(function(prop) {
  return prop.constructor.name === "Object"
 }) // [Object, Object]

但是当我们向arr添加一个对象时; e.g;

 var c = Object.create(null); arr.push(c); 

 var res = arr.filter(function(prop) {
   return prop.constructor.name === "Object"
 }) // `Uncaught TypeError: Cannot read property 'name' of undefined`

c prototypeconstructorundefined。虽然我们确信这不会返回预期的结果

var n = arr.filter(Object.hasOwnProperty, "abc"); // [1, 2]

至少没有返回错误;让我们继续

var n = arr.filter(function(prop, val) {
          return prop.hasOwnProperty(this.valueOf())
        }, "abc"); // [Object abc: 123__proto__: Object]

返回预期结果;虽然我们正在尝试使用

var n = arr.filter(/* function reference */, this /* optional parameters passed */)

  1. 过滤Object{}个对象的数组;即使对象没有定义的原型或构造函数;可选地将JSON字符串"{"abc":123}"转换为对象;虽然我们尚未达到这一目标,但是;

  2. 将属性名称传递给.filter(callback, this)模式,其中this用作属性名称或对象的值;或使用filter.bind.call.apply或其他方法从输入数组中过滤对象 - 而不使用完整

    .filter(function(prop, value) {})

    图案。我们如何将Object.hasOwnProperty()调用强制转换为类似于

    的模式

    .filter(Object.hasOwnProperty, "abc")

  3. 在搜索类似问题并找到JS Array.prototype.filter on prototype method后提及.call.bind.apply。虽然不确定如何实现在过滤具有如上所述的特定属性的对象和对象中描述的方法。

    注意,问题也可以通过destructuring或其他es-6es-7方法解决,与.filter()相比,提供可比较甚至更严格的结果。也就是说,使用.filter()而不是

       function(prop, value) {
    
       }
    

    图案。归还对象;那是Object{};和按属性过滤的对象;按属性值过滤的对象。

    问题:

    1. 如何在不使用匿名函数Object模式的情况下,在传递给Array.prototype.filter()的数组中使用或不使用callback原型或构造函数来过滤对象?

    2. 如何通过将属性名称或值传递给匹配对象而不使用匿名函数Array.prototype.filter()模式来过滤传递给callback的数组中的特定对象?

6 个答案:

答案 0 :(得分:2)

  

如何使用或不使用Object原型或构造函数过滤对象   在一个数组内传递给Array.prototype.filter()而不使用   匿名函数callbackpattern?

根据spec

  

callbackfn应该是一个接受三个参数的函数   返回一个可强制为布尔值true或false的值

Number object(函数的构造函数)确实返回NaN以进行错误的数字转换,但String和Object构造函数不返回false值(是的,filter(Number)也过滤掉0)

var arr = [0,1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]];
arr.filter(Number); //outputs [1, 2, true, 4, 6, 7, 9, Array[1]]

您可以创建客户功能OBJ,

function OBJ(value,index,arr){ return typeof value === "object" && !Array.isArray(value) }
结果集中也欢迎

或数组,然后删除Array.isArray检查

function OBJ(value,index,arr){ return typeof value === "object" }

一起使用时
arr.filter(OBJ); //outputs [{"abc":123},{"def":456}]

答案 1 :(得分:2)

没有创建自己的功能,没有真正的安全方法。此外,它非常复杂,因为Object的定义过于宽泛。

让我们从以下开始:

var types = ['1', 2, true, null, undefined, [], {}, new Date()];

并运行以下内容:

types.map((e) => typeof e);
// ["string", "number", "boolean", "object", "undefined", "object", "object", "object"]

您认为nullObject吗?我不这么认为。您是否认为Array属于Object,因为Array Object的一个实例?我也不确定。

您可以尝试以下内容:

types.map(Object.isExtensible);
// [false, false, false, false, false, true, true, true]

这会从结果中排除null,但数组仍然存在于此处。此处Date Object以及任何其他Object与任何prototype相同,例如new Boolean()也是Object。此外,该对象可能被冻结,此处也不会以Object形式返回。

因此,这两个示例都成功地证明了Object的定义过于宽泛,无法以有用的方式进行真正的处理。

答案 2 :(得分:1)

您似乎想要为具有特定类型的元素过滤数组。将适当的函数传递给filter

array.filter(istype("String"))

您现在只需要编写istype

function istype(type) {
  return function(x) {
    return Object.prototype.toString.call(x) === '[object ' + type + ']';
  }
}

您似乎认为可以通过说filter(Number)等来过滤数字。但这不起作用。 Number只是另一个功能,它会尝试将某些内容转换为数字(检查它是否为数字)。然后,filter根据结果是真实的还是假的来过滤数组。 Number显然会为任何非零数字生成真值,true。对于字符串,对象或其他任何东西,它将返回NaN,这是假的,有奇怪的例外,例如为0返回[]或全空字符串。

与字符串相同。 String只是另一个函数,它试图将某些东西变成字符串。然后,filter根据结果是真实的还是假的来过滤数组。 String将为除非空字符串之外的任何其他内容生成一个真值。

这与解构没有任何关系;为什么你会这么想?您可能想删除帖子中那个不幸的部分。也没有明确你的意思是"在没有回调的情况下调用过滤器" - 使用回调来确定要过滤进出的元素是filter的整个DNA。当你说function(prop, value) { }模式时,你也不清楚你指的是什么模式。

在问题的最后,您会提出两个具体问题:

  

如何在不使用匿名函数callbackpattern的情况下,在传递给Array.prototype.filter()的数组中使用或不使用Object原型或构造函数来过滤对象?

通过提供确定特定元素是否为对象的函数,从输入数组中过滤对象。这不是对象原型或构造函数Object,因此不会帮助您。你必须写一个小函数来传递给filter,它是如何工作的。它可以是匿名的,也可以在别处定义并传入

  

如何通过将属性名称或值传递给匹配对象而不使用匿名函数回调模式来过滤传递给Array.prototype.filter()的数组中的特定对象?

你是什么意思"传递属性名称或值以匹配对象"?您的意思是,过滤掉缺少特定属性名称或值的元素?然后编写一个函数来做到这一点。如果正是在寻找,那么没有内置功能用于此目的。

答案 3 :(得分:1)

不传递回调函数,您可以使用RegExp.prototype.test方法传递正则表达式并绑定正则表达式

var arr = [1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]]

var res = arr.filter(RegExp.prototype.test.bind(/\[object Object\]/));

console.log(res)

这也会匹配包含[object Object]的任何字符串,但字符串似乎不太可能包含那些确切的单词,除非您犯了错误并在数组中包含了字符串化对象。

答案 4 :(得分:1)

在ES6中,以下将对您列出的示例值执行此操作:

arr.filter(Object.isExtensible)

显然,通过调用Object.freezeObject.sealObject.preventExtensions,这将排除已标记为不可扩展的对象。除非你打算使用这些,否则我相信这是有用的。



var arr = [
    /* primitives: */
    2, true, "str", null, undefined, NaN, 
    /* objects */
    new Number(2), {a:1}, Object.create(null), [10], x=>x, new Date(), new Set()
];

var objects = arr.filter(Object.isExtensible);

console.log(objects);




答案 5 :(得分:0)

到目前为止最接近要求的人也匹配Object.create(null)

var res = []; for (let p of arr) /^\{?.+\}$/.test(JSON.stringify(p)) && res.push(p)
相关问题