网站搜索

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


给定

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

我们可以使用 Number 构造函数过滤数组 arr 中的数字项

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

在结果数组中是否预期出现 true 和 [10]?如果我们在 arr 中将 true 替换为 false

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 中索引为 4、7 的对象项,并且我们尝试

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 添加一个对象时;例如;

 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 的 prototype 和 constructor 是 undefined。虽然我们确定这不会返回预期的结果

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

?

提到 .call、.bind 和 .apply,在搜索类似问题并找到关于原型方法 JS Array.prototype.filter 后。然而,不确定如何实现上述描述的同时过滤对象和具有特定属性的对象的方法。

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

   function(prop, value) {

   }

模式。返回对象;即 Object 、{};以及按属性过滤的对象;按属性值过滤的对象。

问题:

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

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

答案#1

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

根据规格

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

Number 对象(函数的构造函数)在错误的 Number 转换时会返回 NaN,但 String 和 Object 构造函数不会返回假值(是的,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}]

答案#2

没有真正的方法可以安全地做到这一点,除非你自己创建一个函数。此外,它非常复杂,因为 Object 的定义过于广泛。

让我们从以下内容开始:

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

并运行以下命令:

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

你认为 null 是一个 Object 吗?我不这么认为。你认为一个 Array 是一个 Object 吗,因为 Array 确实是 Object 的一个实例?我也不确定。

你可以尝试以下方法:

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

这排除了结果中的 null,但数组仍然存在。Date Object 也在这里,任何其他具有任何 prototype 的 Object 也在这里,例如 new Boolean() 也将是一个 Object。此外,该对象可能已被冻结,这里也不会将其作为 Object 返回。

所以这里的两个例子都成功地证明了 Object 的定义太宽泛,不能以一种有用的方式真正处理它。