# Render-help

# 解析 _c, _m, _l

export function renderMixin () {
  // ...
  installRenderHelpers(Vue.prototype)
  // ...
}

export function installRenderHelpers(target: any) {
  // 为 VNode 打上静态标记
  target._o = markOnce
  // 将值转换为数字
  target._n = toNumber
  // 将值转换为字符串形式
  target._s = toString
  // v-for
  target._l = renderList
  // slot 
  target._t = renderSlot
  // 判读两个值是否相等
  target._q = looseEqual
  // indexOf
  target._i = looseIndexOf
  // 静态节点
  target._m = renderStatic
  target._f = resolveFilter
  target._k = checkKeyCodes
  target._b = bindObjectProps
  // 文本节点
  target._v = createTextVNode
  
  // 创建空节点
  target._e = createEmptyVNode
  
  target._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
}

# renderList

/* 
* genFor 处理的 el.for 为解析出来的可迭代对象
* _l(el.for, (alias, iteratior1, iteratior12) => genElement(tag, data, children))
*/
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 (let 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)) {
    // v-for 的是一个对象
    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++) {
        key = keys[i]
        ret[i] = render(val[key], key, i)
      }
    }
  }
  if (!isDef(ret)) {
    ret = []
  }
  // 返回 VNode 数组
  (ret: any)._isVList = true
  // ret => [genElement(x, y, z), ....]
  return ret
}

# renderStatic

export function renderStatic (
  index: number,
  isInFor: boolean
): VNode | Array<VNode> {
  // 缓存
  const cached = this._staticTrees || (this._staticTree = [])
  let tree = cached[index]
  // 已经渲染过 同时不在 v-for 的节点中
  if (tree && !isInFor) return tree
  // 执行 staticRenderFns 数组中指定元素生成 VNode 并缓存
  tree = cached[index] = this.$options.staticRenderFns[index].call(
    this._renderProxy,
    null,
    this
  )
  // 向 el 添加 isStatic=true, key=`__static__${index}`, isOnce=false
  markStatic(tree, `__static__${index}`, false)
  return tree
}

# createElement

export function createElement (
  context: Component,
  tag: any,
  data: any,
  children: any,
  normalizationType: any,
  alwaysNormailze: boolean
): VNode | Array<VNode> {
  if (Array.isArray(data) || isPrimitive(data)) {
    normalizationType = children
    children = data
    data = undefined
  }
  if (isTrue(alwaysNormailze)) {
    normalizationType = ALWAYS_NORMALIZE
  }
  return _createElement(context, tag, data, children, normalizationType)
}

export function _createElement(
  context: Component,
  tag?: string | Class<Component> | Function | Object,
  data?: VNodeData,
  children?: any,
  normalizationType?: number
): VNode | Array<VNode> {
  if (isDef(data) && idDef(data.__ob__)) {
    // data 不能是一个响应式对象
    return createEmptyVNode()
  }
  // component 的 is 属性
  if (isDef(data) && isDef(data.is)) {
    tag = data.is
  }
  if (!tag) {
    return createEmptyVNode()
  }
  // 省略代码 检测唯一键 key 只能是字符串或者数字
  
  
  if (Array.isArray(children) && typeof children[0] ==== 'function') {
    data = data || {}
    data.scopedSlots = { default: children[0] }
    children.length = 0
  }
  // 将子元素进行标准化处理
  if (normalizationType === ALWAYS_NORMALIZE) {
    children = normalizeChildren(children)
  } else if (normalizationType === SIMPLE_NORMALIZE) {
    children = simpleNormalizeChildren(children)
  }
  
  // 重点
  let vnode, ns
  if (typeof tag === 'string') {
    // 平台保留标签、 自定义组件、 不知名标签
    let Ctor
    ns = (context.$vnode && context.$vnode.ns) || config.getTageNamespace(tag)
    // 如果是平台原生标签
    if (config.isReservedTag(tag)) {
      // 报错
      vnode = new VNode(
        config.parsePlatformTagName(tag),
        data,
        children,
        undefined,
        undefined,
        context
      )
    } else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
      // tag 是一个自定义组件
      vnode = createComponent(Ctor, data, context, children, tag)
    } else {
      // 不知名标签
      vnode = new VNode(
        tag,
        data,
        children,
        undefined,
        undefined,
        context
      )
    }
  } else {
    // tag 不是一个字符串
    vnode = createComponent(tag, data, context, children)
  }
  if (Array.isArray(vnode)) {
    return vnode
  } else if (isDef(vnode)) {
    if (isDef(ns)) applyNs(vnode, ns)
    if (isDef(data)) registerDeepBindings(data)
  } else {
    return createEmptyVnode()
  }
}