Javascript Array.prototype.*在类似数组的对象或任何本机/主机对象上的可移植性

Javascript Array.prototype.*在类似数组的对象或任何本机/主机对象上的可移植性,javascript,standards,portability,ecmascript-5,Javascript,Standards,Portability,Ecmascript 5,对于许多Array.prototype函数,ESMA 262 5.1表示它们是有意泛型的,并用对象上的[[Get]]、[[Put]]等操作来描述,但也需要长度属性 因此允许他们处理内置对象,如: obj = {"a":true, "length":10}; Array.prototype.push.call(obj, -1); console.log(obj); // Object { 10: -1, a: true, length: 11 } 对于本机对象,请注意: 推送功能是否能成功应用

对于许多Array.prototype函数,ESMA 262 5.1表示它们是有意泛型的,并用对象上的[[Get]]、[[Put]]等操作来描述,但也需要长度属性

因此允许他们处理内置对象,如:

obj = {"a":true, "length":10};
Array.prototype.push.call(obj, -1);
console.log(obj); // Object { 10: -1, a: true, length: 11 }
对于本机对象,请注意:

推送功能是否能成功应用 对主机对象的访问依赖于实现

参数是宿主对象吗?似乎所有作为节点列表的DOM都是主机对象。它们在现代浏览器中工作

警告 更新@jfriend00 Hm,我没有想到[[Put]]操作。。。在ECMA 5.1中,我发现了有关这种情况的特别说明:

Host objects may implement these internal methods in any manner
unless specified otherwise; for example, one possibility is that
[[Get]] and [[Put]] for a particular host object indeed fetch and
store property values but [[HasProperty]] always generates false.
However, if any specified manipulation of a host object's
internal properties is not supported by an implementation, that
manipulation must throw a TypeError exception when attempted.

所以在糟糕的情况下,你会得到TypeError

如果您想确保它能工作,最好先将其转换为数组

要将类似数组的对象转换为数组,可以使用ES6。目前只有Firefox32支持它,但有一个


或者,[].slice.callarrayLike可以在大多数浏览器上使用。

如果您想确保它可以使用,最好先将其转换为数组

要将类似数组的对象转换为数组,可以使用ES6。目前只有Firefox32支持它,但有一个


或者,[].slice.callarrayLike可以在大多数浏览器上使用。

由于您从未真正得到完整的答案,我将尝试回答您发布的一些问题

参数是宿主对象吗

参数是Javascript语言的一部分,而不是宿主对象。它有一个定义很好的行为,在严格模式下运行时,该行为已被修改。由于参数不会在当前函数调用之后持续存在,即使在闭包中也不会,而且参数也不是可变的,处理arguments对象的常用方法是立即将一个副本复制到一个实数组中,然后可以在该数组中使用所有常规数组方法,并且可以将其保存在闭包中以供本地函数访问

MDN文档警告 这里不太具体地概括某个特定的浏览器。相反,您必须检查特定对象,然后检查浏览器的特定版本。IE的旧版本确实因主机对象不能以这种方式与JavasCript进行互操作而名声大噪,但您确实需要检查特定对象,以了解您可以做什么和不能做什么

nodejs本机对象呢

与浏览器相比,node.js更纯粹的Javascript环境,因为没有DOM,没有窗口对象等。。。您是否有任何想要询问的特定node.js对象?在我使用node.js的有限经验中,我只是看到了实际的js对象,尽管node.js与操作系统的接口有很多地方,所以在这些接口中可能有一些非js对象我还没有遇到,但这是一种可能性

所以在糟糕的情况下,你会得到TypeError

正如我在评论中所说,使用任何试图修改数组的数组对象(如.splice)很可能会导致主机对象出现问题,因为许多主机对象都不打算直接修改。再加上阅读规范,并假设旧的浏览器都遵循规范,而无需进行广泛的测试来验证这可能是危险的。特别是,IE的旧版本以不遵循规范而闻名。所以,再一次,你不能假设在没有适当测试的情况下你会得到一个类型错误

如果您正在寻找一种通用安全的编码方式,那么将类似于数组的宿主对象复制到实际数组中,然后在实际数组上使用数组操作,就永远不会出错。那肯定是安全的。Array.prototype.slice有一个跨浏览器的polyfill,可与所有浏览器一起工作,以便复制到服务器上的实际阵列中。如果您只支持IE9及以上版本,则不需要polyfill


而且,永远不要假设任何更改类似于数组的对象的操作在主机对象上通常是安全的——可能存在特定的异常,但您必须进行大量测试才能确定。我的偏好是编写我知道是安全的代码,并且不需要大量测试来保证安全。每次复制到一个实际的数组中,我都会这样做。

因为你从来没有真正得到一个完整的答案,我将尝试回答你发布的一些问题

参数是宿主对象吗

参数是Javascript语言的一部分,而不是宿主对象。它有一个定义很好的行为,在严格模式下运行时,该行为已被修改。由于参数在当前函数调用之后不会持续存在,甚至在闭包中也不会,而且也不意味着它是可变的,因此处理参数的通常方法是 对象是立即将一个副本复制到一个实际数组中,然后可以在该数组中使用所有常规数组方法,并且它可以持久化为一个闭包,以供本地函数访问

MDN文档警告 这里不太具体地概括某个特定的浏览器。相反,您必须检查特定对象,然后检查浏览器的特定版本。IE的旧版本确实因主机对象不能以这种方式与JavasCript进行互操作而名声大噪,但您确实需要检查特定对象,以了解您可以做什么和不能做什么

nodejs本机对象呢

与浏览器相比,node.js更纯粹的Javascript环境,因为没有DOM,没有窗口对象等。。。您是否有任何想要询问的特定node.js对象?在我使用node.js的有限经验中,我只是看到了实际的js对象,尽管node.js与操作系统的接口有很多地方,所以在这些接口中可能有一些非js对象我还没有遇到,但这是一种可能性

所以在糟糕的情况下,你会得到TypeError

正如我在评论中所说,使用任何试图修改数组的数组对象(如.splice)很可能会导致主机对象出现问题,因为许多主机对象都不打算直接修改。再加上阅读规范,并假设旧的浏览器都遵循规范,而无需进行广泛的测试来验证这可能是危险的。特别是,IE的旧版本以不遵循规范而闻名。所以,再一次,你不能假设在没有适当测试的情况下你会得到一个类型错误

如果您正在寻找一种通用安全的编码方式,那么将类似于数组的宿主对象复制到实际数组中,然后在实际数组上使用数组操作,就永远不会出错。那肯定是安全的。Array.prototype.slice有一个跨浏览器的polyfill,可与所有浏览器一起工作,以便复制到服务器上的实际阵列中。如果您只支持IE9及以上版本,则不需要polyfill


而且,永远不要假设任何更改类似于数组的对象的操作在主机对象上通常是安全的——可能存在特定的异常,但您必须进行大量测试才能确定。我的偏好是编写我知道是安全的代码,并且不需要大量测试来保证安全。每次复制到一个实际的数组时,我都会这样做。

我认为,除非您在所有浏览器和希望支持的浏览器的所有版本中专门测试它们,否则您不能假设任何数组函数都可以在主机对象上工作。特别是,您应该假设如果修改对象(如.push或.splice),它们将不起作用。如果只是将一些元素复制到一个新的数组(如.slice)中,它们更有可能工作。至于node.js,您询问哪些本机对象尚未成为实际数组?响应您的编辑。当且仅当浏览器实际遵循规范时,才会出现TypeError。如果所有浏览器都能完美地遵循所有规范,那么这一切就会容易得多。我坚持我的建议,您必须测试您想要支持的每个浏览器版本/组合。更好的解决方案是立即将任何非数组复制到实际数组中。一般来说,创建副本是一件非常安全的事情,因为所有类似数组的元素都有一个长度,并且通常使用[index]迭代它们,这是创建副本所需的全部。仅供参考,您问题中的第一个代码示例有点无意义。为什么。推入JS对象?你需要一个键和一个值才能成为一个对象的属性。push只提供这个值。这似乎从一开始就不匹配,而且是你永远不应该做甚至尝试去做的事情。@jfriend00:the.push示例并非无稽之谈。.push方法根据对其对象提供的当前.length的分析自动为键提供新索引。例如,这与在jQuery对象上执行相同的操作没有什么不同。@CookieMonester-好的,我明白你的意思。但是,你不会发现我在使用。按非数组。我仍然认为,在非数组对象上使用一系列数组方法的整个推理过程只是一种冒险的编程。如果要对非实际数组的对象执行数组操作,然后将它复制到一个实际的数组中,在这个数组中,你可以拥有完全受支持的方法,而不必考虑什么是有效的,什么是无效的,或者编写你自己的代码,以一种基于你所拥有的对象类型的已知功能可以保证安全的方式来执行操作。我认为你不能假设任何数组都可以运行处理主机对象,除非您在所有浏览器以及希望支持的浏览器的所有版本中专门测试它们。特别地
,您应该假设如果修改对象(如.push或.splice),它们将不起作用。如果只是将一些元素复制到一个新的数组(如.slice)中,它们更有可能工作。至于node.js,您询问哪些本机对象尚未成为实际数组?响应您的编辑。当且仅当浏览器实际遵循规范时,才会出现TypeError。如果所有浏览器都能完美地遵循所有规范,那么这一切就会容易得多。我坚持我的建议,您必须测试您想要支持的每个浏览器版本/组合。更好的解决方案是立即将任何非数组复制到实际数组中。一般来说,创建副本是一件非常安全的事情,因为所有类似数组的元素都有一个长度,并且通常使用[index]迭代它们,这是创建副本所需的全部。仅供参考,您问题中的第一个代码示例有点无意义。为什么。推入JS对象?你需要一个键和一个值才能成为一个对象的属性。push只提供这个值。这似乎从一开始就不匹配,而且是你永远不应该做甚至尝试去做的事情。@jfriend00:the.push示例并非无稽之谈。.push方法根据对其对象提供的当前.length的分析自动为键提供新索引。例如,这与在jQuery对象上执行相同的操作没有什么不同。@CookieMonester-好的,我明白你的意思。但是,你不会发现我在使用。按非数组。我仍然认为,在非数组对象上使用一系列数组方法的整个推理过程只是一种冒险的编程。如果要对非实际数组的对象执行数组操作,然后将它复制到一个实际的数组中,在这个数组中,您拥有完全受支持的方法,对什么有效、什么无效没有任何疑问,或者编写您自己的代码,以一种基于您所拥有的对象类型的已知功能确保安全的方式执行操作。这有什么不同?您使用的正是他询问的概念,以便将其转换为数组,因此您的解决方案受到相同的询问。@CookieMonester和jfriend00一样,仅将元素复制到数组(如slice)中更可能有效。其他修改数组的方法更有可能失败,但在本机对象上也是如此。如果对任何不可变的对象应用变异数组方法,则该对象将失败。他要问的是,通常在宿主对象上使用数组方法是否安全。本机或主机的特定用途超出此点。你最终还是提出了一个回避原始问题的解决方案。这有什么不同?您使用的正是他询问的概念,以便将其转换为数组,因此您的解决方案受到相同的询问。@CookieMonester和jfriend00一样,仅将元素复制到数组(如slice)中更可能有效。其他修改数组的方法更有可能失败,但在本机对象上也是如此。如果对任何不可变的对象应用变异数组方法,则该对象将失败。他要问的是,通常在宿主对象上使用数组方法是否安全。本机或主机的特定用途超出此点。你最终还是提供了一个回避原始问题的解决方案。