2009/12/8 Brendan Eich <bren...@mozilla.com>: > 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".
Ah ok. I agree with Erik then. Even moreso, instanceof doesn't work cross context. >> 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. Maybe I'm imagining things, but I'm pretty sure that on some browsers length is enumerable on arr in var arr = [1,2,3] arr.length = 2; > >> 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@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss > > _______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss