Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

fix(forEach): refined treatment of objects with numeric length property #1938

Closed

Conversation

gonzaloruizdevilla
Copy link
Contributor

fixes #1840
to iterate the object like an array, it must verify one of these rules:

  • it comes from jquery so it must have at least a context property
  • every other property is a number between 0 and the value of
    length property

@IgorMinar
Copy link
Contributor

we can't be iterating over the whole array/object to determine how to handle it. that's way too expensive.

how about doing this instead:

    } else if (isArray(obj) || (JQLite && obj instanceof JQLite) || (jQuery && obj instanceof jQuery)) {

@gonzaloruizdevilla
Copy link
Contributor Author

If only JQLite and jQuery objects are the "special" objects that must be treated like arrays, indeed this is way more faster.

I've changed the test accordingly. However, I'm not sure how to check the jQuery condition. The unit test is only checking explicitly the JQLite one.

@IgorMinar
Copy link
Contributor

I changed your test to use jqLite instead of JQLite - jqLite is either jQuery or JQLite depending on the environment it runs on.. this is how the test verifies that the change works for both.

however there are some problems on safari and IE :-/

http://ci.angularjs.org/job/angular.js-igor/778/console

this is my modified commit: b1ad7976e50d6e8de25e629d997135321a4cd6ef


UPDATE: I fixed the opera failure by using value.innerHTML instead of just value

updated commit is here: 1627088694fe5653d0f9e446b84a387a67ef3d46

can you debug the IE issue?

@IgorMinar
Copy link
Contributor

PR Checklist (Minor Bugfix)

  • Contributor signed CLA now or in the past (if you just signed, leave a comment here with your real name)
  • PR doesn't introduce new api
  • [-] PR doesn't contain a breaking change
  • PR contains unit tests
  • [-] PR contains e2e tests (if suitable)
  • [-] PR contains documentation update (if suitable)
  • PR passes all tests on Travis (sanity)
  • PR passes all tests on ci.angularjs.org (cross-browser compatibility)
  • PR is rebased against recent master
  • PR is squashed into one commit per logical change
  • PR's commit messages are descriptive and allows us to autogenerate release notes (required commit message format)
  • All changes requested in review have been implemented

@IgorMinar
Copy link
Contributor

as expected only IEs are failing now: http://ci.angularjs.org/job/angular.js-igor/780/console

@ghost ghost assigned IgorMinar Feb 8, 2013
@gonzaloruizdevilla
Copy link
Contributor Author

sure, I'll look to the IE issue

@gonzaloruizdevilla
Copy link
Contributor Author

If logged calls to forEach in IE8 and this is what i've found:

forEach is receiving objects of these types:

StaticNodeList: http://msdn.microsoft.com/en-us/library/ie/hh826017(v=vs.85).aspx
NamedNodeMap: http://msdn.microsoft.com/en-us/library/cc849025(v=vs.85).aspx

In IE8, none of these objects has hasOwnProperty and this produces the error.
Both should be treated as an array, so an instanceof check would be enough, at least for StaticNodeList.
Either way, I think it would be necessary to check of hasOwnProperty before using it.

@IgorMinar
Copy link
Contributor

right and also HTMLCollection (in the failing $anchorScroll test).

there seems to be quite a lot of these objects so whitelisting them is not a good option.

now I understand why the original check was is Object + has length prop. it was to support iteration over these very special array like objects.

@gonzaloruizdevilla
Copy link
Contributor Author

I returned to the original approach but in a less naive way. Instead of iterating over the properties, as the test takes the premise that these objects that are like full arrays, the code only checks that the last property is defined.

There is, however, an edge case when length is 0. jqLite, HTMLCollection, StaticNodeList and every other object like these ones must continue to be treated like an array. The downside is that when a plain old object has a length property with a zero value its going to be treated like an array too. I've make an exception with the window object that has a zero length property.

If looked to a few other frameworks, and many have have also this bug. I found that jQuery addressed it in this way.

…like objects

fixes angular#1840
when an object has a numeric length property:
if an object has a length property with a number value of 0, it will
be considered like an array like object
if the value is positive and the object looks like a full dense array
with a property named as length minus one, it will be considered
like an array like object

Signed-off-by: Gonzalo Ruiz de Villa <[email protected]>
@IgorMinar
Copy link
Contributor

thanks for poking at this. the last commit still doesn't cover many usecases.

I was able to craft this patch which I think covers everything that we care about on all browsers: ec54712

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

$resource query action doesn't send right params to the server
2 participants