Allow iterating over smart Arrays that extend/inherit the Array (instance of the Array) or something like arguments (not an instance of the Array).
No change in API
I don't think we can support arbitrary Array-like objects - the line between a actual "object" vs. "array-like" is blurry. We will stick to Array.isArray
in this case. But we can and should support Array subclasses.
Also - since subclassing Array is a ES6+ feature, we will likely implement this when we re-implement the reactivity system with Proxies.
Offtopic: @yyx990803, I've seen in some discussion that you didn't want to switch to proxies for reactivity because it creates a new object instead of editing the initial one, what has changed?
@yyx990803 Sounds good. Thanks.
BTW, all that seems to be necessary to qualify interpreting an object as an array (logging it with square brackets) in V8 seems to be a numerical index
and a function in splice
: ({ length: 0, splice(){} })
As an alternative we could use iterator protocol which works with way more iterable structures than just array and array-likes (Map
, Set
, Iterator
)
@nickmessing that difference is still there so it will introduce some breaking changes, also the browser compatibility constraints means we will only do it for v3.
OFFTOPIC: @yyx990803, if that is already a plan maybe it's a nice idea to have a v3 discussion issue about possible breaking/browser compatibility changes?
@nickmessing currently the only planned change in v3 is the reactivity system and browser compatibility (dropping IE for only evergreen browsers). The breaking changes would be minimal (only in terms of observed object equality) and the API will remain the same.
@yyx990803, what about using v-for
for Map
and Set
? I've seen people asking that once in a while. If support of old browsers is gone then Symbol.iterator
with for of
is available everywhere.
P.S. that solves this issue too
@nickmessing yup, those will also be supported in v3.
Just to clarify, I don't believe subclassing the Array is a ES6+ feature. What if I just inherit it ES5 style?
function Collection () {
Array.apply(this);
}
Collection.prototype = Object.create(Array.prototype);
Object.assign(Collection.prototype, {
...methods
});
That's not true subclassing - see this for more details. Only ES6+ supports something like class Collection extends Array {}
.
What about support for objects defining iteration protocols? So instead of relaying on inheritance, we could check if an object defines an iterator and then use that to iterate? This would probably not break backwards compatibility and could be done already now.
@mitar, as @yyx990803 said few comments ago, v-for will be using Symbol.iterator
in v3 when we drop support for old browsers. Actual implementation works differently and I don't think it's a good idea to support "new" iteration while we support IE9+.
Just for reference, this is how I implemented support for iterators in Meteor's Vue fork. I do not see it breaking anything if it would be already implemented in v2, but this is your call.
@mitar, why not for of
?
That's Evan's call and looks like he decided that to be a part of v3, from my point of view if we support IE9+ we should not have code that will work only in newer browsers.
Hm, good question. I don't know if existing Vue code uses for of
, so I just didn't want to use it myself.
Iteration protocol does not ensure that iterator can be rewound (like generators), which means it will break when render function is called again. Also, array-likes generally don't simply read values from memory but do some extra work which shouldn't be repeated on each render.
That being said I don't think you would need to be able to iterate through array-like or custom object directly. Instead, you need array representation of underlying values (e. g. in a computed property), which will always be a native Array. Or possibly other built-in iterable, when they're supported.
Iteration protocol does not ensure that iterator can be rewound (like generators)
But you can obtain a new iterator object when you want to iterate again?
const iterator = arrayLike[Symbol.iterator]();
And then you iterate. And you can call this as many times as you want. The same happens if you do not manually obtain an iterator, but use JS syntax.
Closing (lack of actionable items before v3)
Most helpful comment
I don't think we can support arbitrary Array-like objects - the line between a actual "object" vs. "array-like" is blurry. We will stick to
Array.isArray
in this case. But we can and should support Array subclasses.Also - since subclassing Array is a ES6+ feature, we will likely implement this when we re-implement the reactivity system with Proxies.