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