6

给定

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]预期的结果数组?如果我们替换falsetruearr

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

 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 prototypeconstructor现在一样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,在搜索了一个类似的Question并找到.bindJS Array.prototype.filter onprototype方法之后。尽管不确定如何实现在过滤对象和具有上述特定属性的对象中描述的方法。.apply

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

   function(prop, value) {

   }

图案。返回对象;即Object, {}; 和按属性过滤的对象;按属性值过滤的对象。


问题:

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

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

4

6 回答 6

2

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

根据规格

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

Number 对象(函数的构造函数)确实返回 NaN 用于错误的 Number 转换,但 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}]
于 2016-03-26T07:24:33.587 回答
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?我不这么认为。您是否认为Arrayas是 a 的一个实例Object,因为 theArray 的一个实例Object?我也不确定。

您可以尝试以下内容:

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

null从结果中排除了 ,但数组仍然存在于此处。在Date Object这里以及任何其他Object与任何prototype,例如new Boolean()也将是一个Object。此外,对象可能会被冻结,并且这也不会作为Object此处返回。

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

于 2016-03-26T07:50:57.137 回答
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,这是错误的,但有一些奇怪的例外情况,例如返回0for[]或全空字符串。

与字符串相同。String只是另一个函数,它试图将某些东西变成一个字符串。然后,filter根据结果是真还是假过滤数组。String将为非空字符串以外的几乎所有内容生成真值。

这与解构无关。为什么你会认为它会呢?您可能想删除帖子中不幸的部分。也不清楚您所说的“在没有回调的情况下调用过滤器”是什么意思——使用回调来确定要过滤哪些元素是filter. 当您说模式时,也不清楚您指的是什么function(prop, value) { }模式。

在你的问题的最后,你问了两个具体的问题:

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

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

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

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

于 2016-03-26T13:16:29.717 回答
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]的字符串,但字符串似乎极不可能包含这些确切的单词,除非您犯了一个错误并将字符串化对象包含在您的数组中。

于 2016-11-07T00:04:10.933 回答
1

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

arr.filter(Object.isExtensible)

Object.freeze显然,这将通过调用、Object.seal或排除已标记为不可扩展的对象Object.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);

于 2016-11-07T11:58:56.743 回答
0

到目前为止最接近的已经能够达到要求,也匹配Object.create(null)

var res = []; for (let p of arr) /^\{?.+\}$/.test(JSON.stringify(p)) && res.push(p)
于 2016-04-06T05:58:47.963 回答