Portability of Array.prototype.* on array like objects or ever native/host objects

谁说我不能喝 提交于 2019-12-11 13:26:49

问题


ESMA 262 5.1 for many Array.prototype functions say that they are intentionally generic and described in terms of [[Get]], [[Put]], etc operations on Object, but also require length property.

So them allowed to work on build-in objects, like:

obj = {"a":true, "length":10};
Array.prototype.push.call(obj, -1);
console.log(obj); // Object { 10: -1, a: true, length: 11 }

For native objects standard have note:

Whether the push function can be applied successfully to a host object is implementation-dependent.

Is arguments host object? Seems that all DOM (as NodeList) are host objects. And them work in modern browsers.

MDN docs warn about < IE9. What about another browsers? What about nodejs native objects? What about Rhino/Nashorn native objects?

UPDATE @jfriend00 Hm, I didn't think about [[Put]] operation... In ECMA 5.1 I found special notes about such situation:

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.

So in bad case you get TypeError!


回答1:


Since you never really got a complete answer, I'll take a stab at answering some of the questions you posted.

Is arguments host object?

arguments is part of the Javascript language, not a host object. It has a pretty well defined behavior which has been modified some when running in strict mode. Since arguments does not persist beyond the current function call (not even in a closure) and since it is not meant to be mutable, the usual way of handling the arguments object is to immediately make a copy into a real array where you can then use all the normal array methods on it and it can persist in a closure to be accessed by a local function.

MDN docs warn about < IE9. What about another browsers?

It's not very specific to generalize here about a particular browser. Instead, you'd have to examine a specific object and then specific versions of a browser. Older versions of IE did have a reputation for having host objects that didn't interoperate as well with Javsacript (in this way), but you'd really have to examine a specific object to know what you could and couldn't do.

What about nodejs native objects?

node.js is much more pure Javascript environment than the browser because there is no DOM, no window object, etc... Did you have any specific node.js objects in mind that you wanted to ask about? In my somewhat limited experience with node.js, I'm just seeing actual JS objects, though there are many places that node.js interfaces with the OS so perhaps there are some non JS objects in those interfaces (I haven't encountered any yet, but that is a possibility).

So in bad case you get TypeError!

As I said in my comments, using any array object that attempts to modify the array such as .splice() is very likely to cause problems with host objects as many host objects are not meant to be modified directly. Plus reading the specification and assuming that older browsers all follow the specification (without extensive testing to verify that) can be dangerous. In particular, older versions of IE are famous for not following the specification. So, again, you can't just assume you would get a TypeError without proper testing.


If you're looking for a general purpose safe way to code, one will never go wrong by copying an array-like host object into an actual array and then using array operations on the actual array. That's guaranteed to be safe. There's a cross-browser polyfill for Array.prototype.slice that works with all browsers for copying into an actual array on the MDN page for .slice(). If you're only supporting IE 9 and up, you don't need the polyfill.

And, one should never assume that any operation that changes the array-like object is generally safe on a host object (there could be specific exceptions, but you'd have to do a lot of testing to be sure). My preference is to write code that I know will be safe and does not require a lot of testing to guarantee that. Copying into an actual array gives me that every time.




回答2:


If you want to be sure it will work, better convert it to an array first.

To convert an array-like object to an array, you can use ES6 Array.from. Currently only Firefox 32 supports it, but there is a polyfill.

Alternatively, [].slice.call(arrayLike) will work on most browsers.



来源:https://stackoverflow.com/questions/25676396/portability-of-array-prototype-on-array-like-objects-or-ever-native-host-objec

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!