_l = this._l = this._l = this._l = this._l = this._l = this._l = this._l = this._l = this._l = this._l

Source location, code is not long, you can read

Three utility functions

isDef

IsDef is short for isDefined, which is the other way around isUndefined, just depending on whether it’s undefined

function isDef (v) {
  returnv ! = =undefined&& v ! = =null
}
Copy the code

isObject

IsObject, which distinguishes original values from objects

function isObject (obj) {
  returnobj ! = =null && typeof obj === 'object'
}
Copy the code

hasSymbol

Used to determine whether the current host environment supports native Symbol and reflect.ownkeys. First check whether Symbol and Reflect exist, and use isNative functions to ensure that Symbol and Reflect. OwnKeys are all native definitions

var hasSymbol =
  typeof Symbol! = ='undefined' && isNative(Symbol) &&
  typeof Reflect! = ='undefined' && isNative(Reflect.ownKeys);

/* Check whether it is a built-in method */
function isNative (Ctor) {
  return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}
Copy the code

renderList

In the SRC /core/instance/render-helpers/index.js installRenderHelpers method, the renderList method is copied to target._l, i.e. This. _l = renderList

The logic is clear, with four cases (you can think of val as the value v-for)

Val is Array, or String

ret = new Array(val.length)
for (i = 0, l = val.length; i < l; i++) {
  ret[i] = render(val[i], i)
}
Copy the code

Val for number

Support number!!

ret = new Array(val)
for (i = 0; i < val; i++) {
    ret[i] = render(i + 1, i)
}
Copy the code

Val for Object

  • Symbol is supported and contains iterators

Iterator defines default iterators for each Object. The built-in types are Array, String, Map, Set, TypedArray, and Object do not

So in order to be able to use iterators, we can define an iterator of our own. Example code:

const obj = {
  age: 1.name: 'liu'[Symbol.iterator]: function* () {
    let properties = Object.keys(this)
    for (let i of properties) {
      yield [i, this[i]]
    }
  }
}

const res = obj[Symbol.iterator]()
console.log('res', res.next())
Copy the code

So, if you need to customize the list order, you can customize an iterator to define the order in which the values are iterated

ret = []
const iterator: Iterator<any> = val[Symbol.iterator]()
let result = iterator.next()
while(! result.done) { ret.push(render(result.value, ret.length)) result = iterator.next() }Copy the code
  • Case where Symbol is not supported

In this case, it is easier to generate an array of objects’ properties from object.key and iterate through it

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)
}
Copy the code

The case where val is not defined

Returns an empty array

if(! isDef(ret)) { ret = [] }Copy the code

PS: Although I think this kind of anomaly should be put at the forefront of personal coding habits, not a problem

conclusion

  • V-for can iterate over numbers and strings
  • Iterators for objects can be customized to implement custom list order
  • TypeArray has iterators, i.e. v-for can render class arrays
  • V-for does exception handling, so when you pass in a value that is not Array, String, Number, Object, v-for renders an empty Array

The source code

import { isObject, isDef, hasSymbol } from 'core/util/index'

/** * Runtime helper for rendering v-for lists. */
export function renderList (val: any, render: ( val: any, keyOrIndex: string | number, index? : number) = >VNode
): ?Array<VNode> {
  let ret: ?Array<VNode>, 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)) {
    if (hasSymbol && val[Symbol.iterator]) {
      ret = []
      const iterator: Iterator<any> = val[Symbol.iterator]()
      let result = iterator.next()
      while(! result.done) { ret.push(render(result.value, ret.length)) result = iterator.next() } }else {
      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 = [] } (ret: any)._isVList =true
  return ret
}
Copy the code