array like objects
Brendan Eich
brendan at mozilla.com
Tue Dec 8 10:36:04 PST 2009
On Dec 8, 2009, at 10:10 AM, Mike Samuel wrote:
>> 1) Does the object have the special semantics around .length? This
>> is
>> potentially useful to know and the normal way to find out doesn't
>> work. Instanceof is affected by setting __proto__, yet the special
>> .length handling persists and instanceof doesn't work for cross-
>> iframe
>> objects.
>
> I think I agree with the bit about length, but __proto__ doesn't work
> on non mozilla interpreters
WebKit JSC implemented too :-/.
> and isn't likely to be standardized.
You got that part right :-).
> I don't see how it's relevant to array-like-ness.
Agreed, but Erik's point here was about instanceof. Not only mutable
__proto__, but mutable bindings for constructors, and the issue of
multiple global objects with their unrelated suites of builtin
constructors, make instanceof less than ideal for deciding "array-like".
> Efficiency is obviously important, but another important distinction
> is whether 'length' should be included in the set of keys iterated
> over,
In ES1-5, length is not enumerable for Array, String, and arguments
objects. Anything array-like, same deal or it's not "like" enough.
> and whether iteration over array-index keys should be in numeric
> order.
I'm suspicious of real code depending on insertion order. Typically
arrays are built front to back so the two are the same. Exceptional
cases may break existing for-in loops that inspect arrays and want
numeric order. This is something to investigate (google codesearch?).
>> But really for..in is pretty sick for arrays. It will convert every
>> single index in the array to a string. That's not something to be
>> encouraged IMHO.
>
> Also agreed.
Yes, that is an ES1 change from my Netscape implementation. It is
costly enough that optimizing implementations use memoized or static
strings for small integer literals!
Yet for-in on an array-like is attractive, especially in light of
comprehensions and generator expressions. One way forward would be to
change to number type under opt-in Harmony versioning. Another option
is new syntax, but that requires opt-in versioning anyway, and it's
not clear to me that changing for-in on Arrays, or on all array-likes,
to return numbers for indexes, is an incompatibility that we could not
"get away with".
If anyone knows of real-world code that would be broken by the type of
the for-in loop variable not always being string, I'm all ears.
/be
>
>
>> --
>> Erik Corry
>
>
>
> Prototype.js dodges this problem by adding an each method to
> Array.prototype and others. This obviously fails for cross-context
> Arrays, and also suffers from the large sparse array and missing
> non-array-index properties problems.
>
> It does switch on arrays in places, and does so inconsistently though
> -- in one case (unnecessarily?) filtering out arguments objects?
> if (Object.isArray(item) && !('callee' in item)) {
> for (var j = 0, arrayLength = item.length; j < arrayLength; j+
> +)
> array.push(item[j]);
> } else {
>
> function flatten() {
> return this.inject([], function(array, value) {
> if (Object.isArray(value))
> return array.concat(value.flatten());
> array.push(value);
> return array;
>
> dojo.clone does
> if(d.isArray(o)){
> r = [];
> for(i = 0, l = o.length; i < l; ++i){
> if(i in o){
> r.push(d.clone(o[i]));
> }
> }
> }else{
> // generic objects
> r = o.constructor ? new o.constructor() : {};
> }
> dojo.isArray = function(/*anything*/ it){
> // summary:
> // Return true if it is an Array.
> // Does not work on Arrays created in other windows.
> return it && (it instanceof Array || typeof it == "array"); //
> Boolean
> }
> dojo.isArrayLike = function(/*anything*/ it){
> // summary:
> // similar to dojo.isArray() but more permissive
> // description:
> // Doesn't strongly test for "arrayness". Instead, settles for
> "isn't
> // a string or number and has a length property". Arguments objects
> // and DOM collections will return true when passed to
> // dojo.isArrayLike(), but will return false when passed to
> // dojo.isArray().
> // returns:
> // If it walks like a duck and quacks like a duck, return `true`
> return it && it !== undefined && // Boolean
> // keep out built-in constructors (Number, String, ...) which
> have length
> // properties
> !d.isString(it) && !d.isFunction(it) &&
> !(it.tagName && it.tagName.toLowerCase() == 'form') &&
> (d.isArray(it) || isFinite(it.length));
> }
> and dojo uses these definitions to do type coercion
> }else if(!dojo.isArray(content)){
> //To get to this point, content is array-like, but
> //not an array, which likely means a DOM NodeList. Convert it now.
> content = dojo._toArray(content);
>
>
> The closure library similarly defines both isArray and isArrayLike,
> but with differences (
> http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/base.js
> ):
> goog.isArrayLike = function(val) {
> var type = goog.typeOf(val);
> return type == 'array' || type == 'object' && typeof val.length
> == 'number';
> };
> which is then used in many places (
> http://www.google.com/codesearch?q=goog.isArrayLike+package%3Ahttp%3A%2F%2Fclosure-library%5C.googlecode%5C.com&origq=goog.isArrayLike
> ), e.g. in iter.js
> goog.iter.forEach = function(iterable, f, opt_obj) {
> if (goog.isArrayLike(iterable)) {
>
>
> MooTools is the only library I looked at that does not check
> array-likedness. They do something similar to prototype by
> monkey-patching Array, which will fail for cross-context arrays. They
> do extend the concept of length to their Hash class:
> getLength: function(){
> var length = 0;
> for (var key in this){
> if (this.hasOwnProperty(key)) length++;
> }
> return length;
> }
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
More information about the es-discuss
mailing list