为何有此一问?
目前的前端框架中,vue,react是使用人数比较多的两个,他们中间都定义了一些生命周期函数,Vue的created,mounted,react的componentDidMount,componentWillReceiveProps 等等
我们在工作中经常使用这些函数,但是有时候似乎也需要去思考一下,这些函数具体是如何实现的
钩子函数是什么
钩子函数是一种隔离变化的手段,在父类中容易变化的地方放置钩子,子类可以根据这个钩子决定要不要执行某些操作。比如我有一台打印机,打印机有一个print方法,但是我有可能需要打印彩色或者黑白,这个时候就可以在父类中添加一个钩子方法,用来隔离这种变化。
var Printer = function (){}Printer.prototype.printBlack=funciton(){ console.log('black')}Printer.prototype.printColor=function(){ console.log('color')}Printer.prototype.hook = function(){ return true; // 默认打印黑白}Printer.prototype.init = function(){ if(this.hook()){ this.printBlack() } this.printColor();}// 子类重写hook方法var ChildPrinter = function(){};ChildPrinter.prototype = new Printer();ChildPrinter.hook=function(return window.confirm('打印黑白照片?'));// 实例对象var myPrinter = new ChildPrinter(); myPrinter.init();
Vue中的钩子函数有哪些
vue 的钩子函数名称定义在src/shared/constants.js文件中,有以下几个
export const LIFECYCLE_HOOKS = [ 'beforeCreate', 'created', 'beforeMount', 'mounted', 'beforeUpdate', 'updated', 'beforeDestroy', 'destroyed', 'activated', 'deactivated', 'errorCaptured']
Vue中的钩子函数时如何执行的
这里只说个大概,毕竟源码我也没有参透,在lifecycle.js中定义了一个callHook方法, 代码如下
export function callHook (vm: Component, hook: string) { const handlers = vm.$options[hook] if (handlers) { for (let i = 0, j = handlers.length; i < j; i++) { try { handlers[i].call(vm) } catch (e) { handleError(e, vm, `${hook} hook`) } } } if (vm._hasHookEvent) { vm.$emit('hook:' + hook) }}
它接受两个参数: vue组件实例和钩子名称,然后判断实例的$options中是否存在这个钩子函数,如果存在,则在该实例上执行这个钩子函数。
初始化的时候,调用了两个钩子,beforeCreat 和 created, 代码如下:
Vue.prototype._init = function (options?: Object) { const vm: Component = this // a uid vm._uid = uid++ let startTag, endTag /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { startTag = `vue-perf-start:${vm._uid}` endTag = `vue-perf-end:${vm._uid}` mark(startTag) } // a flag to avoid this being observed vm._isVue = true // merge options if (options && options._isComponent) { // optimize internal component instantiation // since dynamic options merging is pretty slow, and none of the // internal component options needs special treatment. initInternalComponent(vm, options) } else { vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ) } /* istanbul ignore else */ if (process.env.NODE_ENV !== 'production') { initProxy(vm) } else { vm._renderProxy = vm } // expose real self vm._self = vm initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate') initInjections(vm) // resolve injections before data/props initState(vm) initProvide(vm) // resolve provide after data/props callHook(vm, 'created') /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { vm._name = formatComponentName(vm, false) mark(endTag) measure(`vue ${vm._name} init`, startTag, endTag) } if (vm.$options.el) { vm.$mount(vm.$options.el) } }
同理,其他的钩子函数,也是在需要执行某些操作或者变化时调用
总结
为了隔离某些变化
定义在父类中
在需要执行特定操作时调用
每篇文章尽量不超过1000字,觉得对你有帮助的话----欢迎关注,点赞,转发,评论。。。