[TOC] >[success] # 分析init ~~~ 1.整个snabbdom 核心就是patch,进行新老虚拟dom比较,因此首先需要看init这里做了什么 ,因为init返回值是patch 函数,init 的功能:init(modules, domApi),返回 patch() 函数 2.抛开init 中间其他逻辑,其实主要做的就是将这些钩子函数就是类似vue 的声明周期函数 进行初始化保存init() 在返回 patch() 之前,首先收集了所有模块中的钩子函数存储到 cbs 对象中 ~~~ >[danger] ##### init 代码 -- src/snabbdom.ts ~~~ 1.下面是init 的代码片段,采用了闭包的方式,思考为什么这里使用的闭包,先看init 的使用 let patch = init([]) let patchOldVnode = patch(newVnode,oldVnode) patchOldVnode = patch(newVnode,patchOldVnode ) 这使用闭包的好处,两次调用patch,他们的配置都是init 传入的参数,因为闭包延长了参数的作用域链 可以让后来的patch 都共享init传入的配置参数 1.1.举个例子 const patch = init(['a', 'b', 'c']) patch() // [ 'a', 'b', 'c' ] patch() // [ 'a', 'b', 'c' ] 将这个例子转化成类,可以理解成init函数参数就是初始化构造函数,patch 就是这个对象的一个方法 class Init { constructor(cfgs) { this.cfgs = cfgs } patch() { console.log(this.cfgs) } } const init = new Init(['a', 'b', 'c']) init.patch() // [ 'a', 'b', 'c' ] init.patch() // [ 'a', 'b', 'c' ] 2.init 函数第一个参数为模块,这些提供的模块会有钩子函数,'hooks'列出了所有的钩子函数, 将这些模块的钩子函数按照'hooks'提供的进行分类'最终构建的 cbs 对象的形式 cbs = { create: [fn1, fn2], update: [], ...}' ~~~ ~~~ const hooks: (keyof Module)[] = ['create', 'update', 'remove', 'destroy', 'pre', 'post' ]; export function init(modules: Array < Partial < Module >> , domApi ? : DOMAPI) { let i: number, j: number, cbs = ({} as ModuleHooks); // 初始化转换虚拟节点的 api const api: DOMAPI = domApi !== undefined ? domApi : htmlDomApi; // 把传入的所有模块的钩子方法,统一存储到 cbs 对象中 // 最终构建的 cbs 对象的形式 cbs = [ create: [fn1, fn2], update: [], ... ] for (i = 0; i < hooks.length; ++i) { // cbs['create'] = [] cbs[hooks[i]] = []; for (j = 0; j < modules.length; ++j) { // const hook = modules[0]['create'] const hook = modules[j][hooks[i]]; if (hook !== undefined) { (cbs[hooks[i]] as Array < any > ).push(hook); } } } ……………… return function patch(oldVnode: VNode | Element, vnode: VNode): VNode {} } ~~~