网站首页 > 技术文章 正文
前言
这个面向中高级Web前端的面经系列文章,到此便接近尾声了。是不是还有继续出,这个要看接下来的时间安排了。
小团体有个朋友说,他准备更新一些android-kotlin从入门到上手写业务的文章。所以关注我的Web前端的朋友们,不着急,先休息休息,消化消化之前的文章,提前预祝跳槽的朋友,有个好东家~!
本系列文章链接如下:
“金三银四”,让我们愉快的开始准备Web面经吧:JavaScript-上
元宵节,猿宵节,写代码之余面经走一波:JavaScript篇
正文
1. nextTick
在下次dom更新循环结束之后执行延迟回调,可用于获取更新后的dom状态
- 新版本中默认是mincrotasks, v-on中会使用macrotasks
- macrotasks任务的实现:
- setImmediate / MessageChannel / setTimeout
2. 生命周期
- _init_
- initLifecycle/Event,往vm上挂载各种属性
- callHook: beforeCreated: 实例刚创建
- initInjection/initState: 初始化注入和 data 响应性
- created: 创建完成,属性已经绑定, 但还未生成真实dom
- 进行元素的挂载: $el / vm.$mount()
- 是否有template: 解析成render function*.vue文件: vue-loader会将<template>编译成render function
- beforeMount: 模板编译/挂载之前
- 执行render function,生成真实的dom,并替换到dom tree中
- mounted: 组件已挂载
- update:
- 执行diff算法,比对改变是否需要触发UI更新
- flushScheduleQueuewatcher.before: 触发beforeUpdate钩子 - watcher.run(): 执行watcher中的 notify,通知所有依赖项更新UI
- 触发updated钩子: 组件已更新
- actived / deactivated(keep-alive): 不销毁,缓存,组件激活与失活
- destroy:
- beforeDestroy: 销毁开始
- 销毁自身且递归销毁子组件以及事件监听
- remove(): 删除节点
- watcher.teardown(): 清空依赖
- vm.$off(): 解绑监听
- destroyed: 完成后触发钩子
上面是vue的声明周期的简单梳理,接下来我们直接以代码的形式来完成vue的初始化
new Vue({}) // 初始化Vue实例 function _init() { // 挂载属性 initLifeCycle(vm) // 初始化事件系统,钩子函数等 initEvent(vm) // 编译slot、vnode initRender(vm) // 触发钩子 callHook(vm, 'beforeCreate') // 添加inject功能 initInjection(vm) // 完成数据响应性 props/data/watch/computed/methods initState(vm) // 添加 provide 功能 initProvide(vm) // 触发钩子 callHook(vm, 'created') // 挂载节点 if (vm.$options.el) { vm.$mount(vm.$options.el) } } // 挂载节点实现 function mountComponent(vm) { // 获取 render function if (!this.options.render) { // template to render // Vue.compile = compileToFunctions let { render } = compileToFunctions() this.options.render = render } // 触发钩子 callHook('beforeMounte') // 初始化观察者 // render 渲染 vdom, vdom = vm.render() // update: 根据 diff 出的 patchs 挂载成真实的 dom vm._update(vdom) // 触发钩子 callHook(vm, 'mounted') } // 更新节点实现 funtion queueWatcher(watcher) { nextTick(flushScheduleQueue) } // 清空队列 function flushScheduleQueue() { // 遍历队列中所有修改 for(){ // beforeUpdate watcher.before() // 依赖局部更新节点 watcher.update() callHook('updated') } } // 销毁实例实现 Vue.prototype.$destory = function() { // 触发钩子 callHook(vm, 'beforeDestory') // 自身及子节点 remove() // 删除依赖 watcher.teardown() // 删除监听 vm.$off() // 触发钩子 callHook(vm, 'destoryed') }
3. 数据响应(数据劫持)
看完生命周期后,里面的watcher等内容其实是数据响应中的一部分。数据响应的实现由两部分构成: 观察者( watcher ) 和 依赖收集器( Dep ),其核心是 defineProperty这个方法,它可以 重写属性的 get 与 set 方法,从而完成监听数据的改变。
- Observe (观察者)观察 props 与 state
- 遍历 props 与 state,对每个属性创建独立的监听器( watcher )
- 使用 defineProperty 重写每个属性的 get/set(defineReactive)
- get: 收集依赖
- Dep.depend()watcher.addDep()
- set: 派发更新
- Dep.notify()
- watcher.update()
- queenWatcher()
- nextTick
- flushScheduleQueue
- watcher.run()
- updateComponent()
大家可以先看下面的数据相应的代码实现后,理解后就比较容易看懂上面的简单脉络了。
let data = {a: 1} // 数据响应性 observe(data) // 初始化观察者 new Watcher(data, 'name', updateComponent) data.a = 2 // 简单表示用于数据更新后的操作 function updateComponent() { vm._update() // patchs } // 监视对象 function observe(obj) { // 遍历对象,使用 get/set 重新定义对象的每个属性值 Object.keys(obj).map(key => { defineReactive(obj, key, obj[key]) }) } function defineReactive(obj, k, v) { // 递归子属性 if (type(v) == 'object') observe(v) // 新建依赖收集器 let dep = new Dep() // 定义get/set Object.defineProperty(obj, k, { enumerable: true, configurable: true, get: function reactiveGetter() { // 当有获取该属性时,证明依赖于该对象,因此被添加进收集器中 if (Dep.target) { dep.addSub(Dep.target) } return v }, // 重新设置值时,触发收集器的通知机制 set: function reactiveSetter(nV) { v = nV dep.nofify() }, }) } // 依赖收集器 class Dep { constructor() { this.subs = [] } addSub(sub) { this.subs.push(sub) } notify() { this.subs.map(sub => { sub.update() }) } } Dep.target = null // 观察者 class Watcher { constructor(obj, key, cb) { Dep.target = this this.cb = cb this.obj = obj this.key = key this.value = obj[key] Dep.target = null } addDep(Dep) { Dep.addSub(this) } update() { this.value = this.obj[this.key] this.cb(this.value) } before() { callHook('beforeUpdate') } }
尾声
汗--!没想到才写一半就这么多内容了,为了阅读体验,决定分上下俩部分发。后续文章可以关注我,翻看历史文章~
猜你喜欢
- 2025-06-13 大型前端应用如何做系统融合?(系统前端怎么做)
- 2024-10-04 小厂一面:30分钟速通,拿下一血(前端)
- 2024-10-04 【中大厂前端面试百问】这不迷死你?
- 2024-10-04 写给准备跳槽的Web前端工程师(第二章)
- 2024-10-04 网络安全、Web安全、渗透测试之笔经面经总结
- 2024-10-04 写给准备跳槽的Web前端工程师(第三章)
- 2024-10-04 燃数科技前端25-40K*14薪一面超简单,下周二面啦
- 2024-10-04 前端面试总结 前端面试题目100及最佳答案
- 2024-10-04 前端社招一点面试记录 社招前端面试自我介绍
- 2024-10-04 Java大佬分享:字节跳动面经分享,从JVM到线程池
你 发表评论:
欢迎- 523℃Oracle分析函数之Lag和Lead()使用
- 520℃几个Oracle空值处理函数 oracle处理null值的函数
- 517℃Oracle数据库的单、多行函数 oracle执行多个sql语句
- 504℃0497-如何将Kerberos的CDH6.1从Oracle JDK 1.8迁移至OpenJDK 1.8
- 501℃Oracle 12c PDB迁移(一) oracle迁移到oceanbase
- 493℃【数据统计分析】详解Oracle分组函数之CUBE
- 472℃Oracle有哪些常见的函数? oracle中常用的函数
- 471℃最佳实践 | 提效 47 倍,制造业生产 Oracle 迁移替换
- 最近发表
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端富文本编辑器 (47)
- 前端路由 (61)
- 前端数组 (73)
- 前端排序 (47)
- 前端定时器 (47)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle 中文 (51)
- oracle的函数 (57)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)