在写一个项目的时候但愿使用Map来进行遍历,而后我取出了Map的keys,keys是一个Map Iterator
(迭代器,ES6引入的Symbol.iterator
)类型,这时我尝试使用v-for
来对迭代器进行遍历,固然个人指望是可以遍历出来。 咱们都知道vue的v-for
提供了两种遍历方式,vue
v-for="item in items"
v-for="item of items"
复制代码
而js中能够使用bash
for (index in items)
for (item of items) // 这种写法支持对迭代器的遍历
复制代码
这时我不由就想,既然如此,v-for
当中of
的遍历方式应该是支持迭代器的遍历的,可是事实尝试下来是不能够的,那么为何不能够呢,而后就去翻查了一下Vue的源码,从中找到了这么一段代码。测试
/**
* Runtime helper for rendering v-for lists.
*/
function renderList (
val,
render
) {
var ret, i, l, keys, key
if (Array.isArray(val) || typeof val === 'string') {
ret = new Array(val.length)
for (i = 0, l = val.length; i < l; i++) {
ret[i] = render(val[i], i)
}
} else if (typeof val === 'number') {
ret = new Array(val)
for (i = 0; i < val; i++) {
ret[i] = render(i + 1, i)
}
} else if (isObject(val)) {
keys = Object.keys(val)
ret = new Array(keys.length)
for (i = 0, l = keys.length; i < l; i++) {
key = keys[i]
ret[i] = render(val[key], key, i)
}
}
if (isDef(ret)) {
(ret)._isVList = true
}
return ret
}
复制代码
我尝试在该段代码中打上了断点,而后发现迭代器自己是一个Object类型(ES5没有Symbol),可是Map Iterator
的Object.keys(val)
则是一个空对象[]
,一个空的keys
,因此此处不会产生遍历而后进行render
。ui
既然没有判断出是一个Iterator那么我就添加一个判断,因为刚开始觉得不能使用ES5以上的语法,修修改改了好屡次,写出了以下的代码,其实这里能够判断类型是否为Symbol.iterator
this
...
} else if (isObject(val)) {
keys = Object.keys(val)
if (keys.length === 0 && val.toString().indexOf('Iterator') > -1) { // 多是个迭代器
ret = []
i = 0
while (true) {
if (typeof val.next !== 'function') {
break
}
var next = val.next()
if (next.done) {
break
}
ret.push(render(next.value, i++))
}
} else {
ret = new Array(keys.length)
for (i = 0, l = keys.length; i < l; i++) {
key = keys[i]
ret[i] = render(val[key], key, i)
}
}
}
...
复制代码
Symbol类型有个方法是Symbbol.toStringTag
spa
Symol.toStringTag
A string value for the default description of an Object. Used by
Object.prototype.toString()prototype
查阅资料看到了这么一段话,那么我就是用toString方法去取出迭代器的description而后使用indexOf去判断是否包含Iterator来区分是否是一个迭代器。
这里使用了while却没有使用for...of的写法, 因为修改的是dist的文件因此不敢尝试ES5+的写法。 而后一切都看起来很完美,可是运行的时候却走到了handleError(e, vm, "render")
一个ERROR分支...百思不得其解...
通过了N轮的断掉调试,我终于定位了到问题的所在。
因为测试的时候是基于项目作的,项目用的ElementUI,其中用到了form组件,层层定位发现是v-model的值为空形成的Error,而后写了一份简单的v-for发现居然真的能够了。调试
template...
<div v-for="item of iterator">
{{item}}
</div>
script...
data () {
return {
iterator: this.getIterator()
}
},
methods: {
getIterator () {
let map = new Map()
map.set('title', '')
map.set('value', '')
return map.keys()
}
}
output...
title
value
复制代码
虽然我在Vue上作了一个ES5+的尝试不知道合不合理,可是在这个探索的过程当中学到了不少,但愿能对你们有所帮助。
其中了解了Symbol类型到底是个怎样的类型,了解了迭代器的实现,实践了断点定位问题等等...一个晚上的付出没白费,仍是比较欣喜的。code
I'm 一个渴望成长的码农orm