【问题标题】:How to filter Object using Array.prototype.filter?如何使用 Array.prototype.filter 过滤对象?
【发布时间】:2016-03-26 06:57:00
【问题描述】:

给定

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] 是否会出现在结果数组中?如果我们用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 添加一个对象时;例如;

 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`

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

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

?

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

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

   function(prop, value) {

   }

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


问题:

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

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

【问题讨论】:

  • 为什么不想使用匿名函数?对我来说,这听起来像 我不想在 JavaScript 中使用 var
  • @guest271314 你能探索一下这个arr.filter(Object.getNotifier); 它的输出是一个错误,但它会检查你想要的。
  • 我不确定您是否理解 NumberString 作为 filter 函数的参数的作用?它们是 makeNumbermakeString,而不是 isNumberisString - 传递为谓词。
  • @guest271314 [0,1, 2, "a"].filter(Number); // [1, 2] 因为 0 是虚假值。
  • SO 不是博客或讨论组。请不要在阅读最新答案和 cmets 后将您的帖子变成对您的心态的持续评论。如果您对评论有回应。回复另一条评论。

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


【解决方案1】:

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

根据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}]

【讨论】:

  • 什么对象有length 属性?
  • var distance = { length: 1000 }Array?
  • @guest271314 不确定你的意思,因为typeof [] 返回"object"
  • @gurvinder372 是的。 arr.filter(OBJ) // [Object, Object, Array[1]] ;在回答arr.filter(OBJ); //outputs [{"abc":123},{"def":456}] ?
  • @guest271314 这种带有过滤器的 Object.hasOwnProperty 的行为很奇怪,已经发布了这个相关问题stackoverflow.com/questions/36233124/…
【解决方案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 吗?我不这么认为。您是否认为ArrayObject,因为Array Object 的一个实例?我也不确定。

您可以尝试以下方法:

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

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

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

【讨论】:

  • 在 JS 中有一个非常明确的定义是什么构成了一个 objectObject(o) === o 产生 true 的所有东西。
  • 如果不创建自己的函数,就没有真正的安全方法。应该省略“安全”一词或用“根本”一词代替。此外,“非常复杂”可能是夸大其词。多年来,人们一直在研究如何测试对象性(通过不同的标准),而且这个话题已经非常枯燥了。
【解决方案3】:

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

array.filter(istype("String"))

你现在只需要写istype

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

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

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

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

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

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

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

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

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

【讨论】:

  • 该问题源于尝试确定是否可以从数组中过滤对象;问题主要是关于对象,而不是字符串或数字类型 1) 没有明确写 function(x) {//perform check} 并使用现有的内置方法;例如,我们可以使用.filter(Array.isArray) 从输入数组中过滤数组; 2)既然我们知道我们可以使用 return Object.prototype.toString.call(x) === '[object Object]'; ,我们如何将它传递给 .filter() 以使用类似的模式作用于 x ;例如,.filter(Object.prototype.toString, "[object Object]")?
  • 此外,如果我们可以通过传递对内置函数的引用来过滤对象,我们可以在.filter() 使用.bindthisArg 选项,而不需要设置@ 987654349@,但是要传入,例如,一个属性名称,以具有两者的能力 3) 从输入数组中过滤对象;和 4) 从数组中过滤特定对象; 4) 两者都没有实际定义.filter() 之外的函数 - 但使用现有的内置方法?例如var arr = [0, [], {"abc":123}];我们希望能够按类型和属性名称过滤{"abc":123}
  • e.g., 5) arr.filter(RegExp.prototype.test.bind(Object.prototype.toString.bind(/* how do we bind here*/, "[object Object]")), "abc") 检查项目是否为对象 - > 检查作为 thisArg 传递的属性,然后调用 test.那篇文章只是传达问题的前提的一个例子。
【解决方案4】:

在不传递回调函数的情况下,您可以通过使用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] 的字符串,但字符串似乎不太可能包含这些确切的单词,除非您犯了一个错误并在数组中包含了字符串化的对象。

【讨论】:

  • 当数组中出现Object.create(null) 时产生异常。也不包括[10]x=>xnew Date()new Set()new Number(2)、...
  • @trincot - 我试图省略数组、函数、日期、集合、数字和其他不仅仅是普通对象的东西,因此检查[object Object],所以我会说它非常接近。 Object.create(null) 也不是一个真正的“普通”对象,因为它不是从 Object 继承的,但如果它不抛出它会更好,但它很难修复。
  • @adeneo var a = []; a.toString = () => '[object Object]'; ('' + a) === '[object Object]'; stackoverflow.com/a/40456709
  • @adeneo 如何首先调用JSON.stringify() 才能使用RegExp /^\{?.+\}$/
  • @guest271314 - 正如我所说的,我认为没有办法可以确定地识别对象,原型可以更改,字符串化的内容可以更改,并且有这么多让你构造最奇怪的对象的新方法,这几乎是不可能的,更何况没有一个可以比较各种事物的冗长回调函数。我认为这个解决方案只是将本机方法传递给filter,它最接近于对普通对象进行识别,即使它确实在相同的字符串和更改的数组等上失败。
【解决方案5】:

在 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);

【讨论】:

  • [10] 不应匹配。最初的问题意图是匹配普通对象。没有考虑DateSetx=>x 是什么?
  • 啊,x=>xfunction function;虽然不应该匹配。
  • 我实际上已经想到了这一点,并在 cmets here 中提出了建议,但它并没有做 OP 想要的,因为它对任何对象返回 true (这是可扩展的当然),而不仅仅是普通的对象。
  • 那么如果你想寻找一个具有length属性的对象呢? [10] 会不会匹配?如果一个函数有其他属性分配给它(有时这样做是为了在构造函数上存储静态变量)怎么办?如果一个对象通过添加方法并使其可迭代而成为类数组怎么办? ...当您使用方法装饰对象时,它是否停止成为 plain 对象?什么时候一个对象变成一个对象?关键是所有这些东西都是对象,要做出区分几乎是人为的,是一条灰色的分隔线。
  • 另请参阅this 对您类似问题的回答,该问题也将 all 对象标识为对象,正如我认为的那样——其他定义很容易变得模棱两可。
【解决方案6】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-21
    • 2020-09-13
    • 2018-12-14
    • 1970-01-01
    • 1970-01-01
    • 2019-08-08
    • 2015-08-23
    • 2017-02-18
    相关资源
    最近更新 更多