自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(66)
  • 收藏
  • 关注

原创 2021前端算法面试

github地址:https://github.com/GuoLizhi/algorithm,欢迎star~一起学习项目简介本项目主要分为两个部分基础数据结构:会使用Java和TypeScript实现底层的数据结构,并考虑数据结构中每个操作的时间复杂度leetcode算法:算法主要会记录在本仓库的issue中,leetcode的每一个分类我都以标签的形式标记出来,欢迎参考学习算法是一个漫长的过程,没法靠突击,只能一步一步慢慢积累。数据结构数据结构Java版TypeScr.

2021-02-23 14:40:06 457

原创 2021 前端面试点总结

以下内容收集于各个技术网站,总结在我们github上https://github.com/GuoLizhi/awesomejs, 求star~1. CSS相关flex2. 设计模式相关单例模式3. 工程化CSRFXSSwebpack性能优化4. 手写JavaScript代码系列apply实现原理bind实现原理call实现原理将字符串复制到剪切板创建一个文件夹函数柯里化防抖函数简易版的深拷贝判断当前处于移动端还是桌面端判断父元素是否包含子元素检查指定的元

2021-02-23 14:28:47 452 1

原创 简单的mvvm实现

// eslint-disable-next-line no-unused-varsclass MVVM { constructor (options = {}) { this.options = options this.observe(options.data) const root = document.querySelector(options.el) this.compile(root) } observe (data) { Object.k

2020-11-17 17:16:13 2824

原创 Vue Compile原理分析

Vue中Compile是一个非常复杂的内容,Compile的主要作用是解析模板,生成渲染模板的render, 而render的作用主要是为了生成VNode, Compile主要分为3大块:parse 接受template原始模板,按着模板的节点和数据生成对应的astoptimize 遍历ast的每一个节点,标记静态节点,这样就知道哪部分不会变化,于是在页面需要更新时,减少去对比这部分DOM,提升性能generate 把前两步生成完善的ast,组成render字符串,然后将render字符串通过new

2020-09-22 19:20:45 3540 2

原创 Vue Render原理分析

1. 主要renderrender的主要作用就是执行Compile生成的render函数,然后得到返回的VNode<div :data="data">{{data}}</div>比如以上的一段模板会生成如下的render函数function render() { with(this) { return _c('div', { attrs: { data: 111 } }, [_v(111)]) }}上面生

2020-09-22 19:20:13 612

原创 Vue Diff原理分析

Diff的出现,是为了减少更新量,找到最小差异部分DOM,只更新差异部分DOM就好了,这样消耗就会小一些。Vue2.x中的diff只会对新旧节点中父节点是相同节点的那一层子节点进行比较。只有当新旧节点是相同节点的时候,才会去比较他们各自的子节点。新旧VNode进行比较的过程中,不会对这两棵VNode树进行修改,而是以比较结果直接对真实DOM进行修改。比如说在比较VNode的过程中,发现某个节点需要移动,此时不会直接移动VNode中的节点,而是直接移动DOM。vm._update()比较新旧VNode树,

2020-09-22 19:19:30 372

原创 Vue nextTick原理分析

this.name = 1;this.name = 2;this.name = 3;为什么只会执行一次?这是nextTick回调和watcher过滤的结果。当数据变化后,将watcher.update函数存放进nextTick的回调数组中,并且会做过滤。通过watcher.id来判断回调数组中是否已经存在这个watcher的更新函数,如果不存在才会push。之后next遍历这个无重复id的回调数组,便会执行更新。因此当3次修改同一个数据时,仅会有一个watcher.update进入回调数组,从而页

2020-09-18 15:54:56 927 2

原创 Vue Events模块原理分析

Vue中事件大致分为4类自定义事件DOM事件组件DOM事件组件自定义事件自定义事件主要由两部分组成事件存储器绑定事件,触发事件,解绑事件Vue的每个实例都会有一个_events对象,用来存放本实例上注册的自定义事件,绑定自定义事件的大致流程如下this.$on 绑定事件this.$emit 触发事件this.$off 解绑事件如果需要给组件绑定原生DOM事件,需要加上native这个修饰符。组件绑定的DOM事件,在父实例解析完毕才开始挂载,遇到子元素是组件,然后去解析内部

2020-09-17 14:51:14 2978

原创 Vue 创建组件外壳VNode原理分析

创建组件VNode<div> <test></test></div>上面这个页面被解析成了一个渲染函数function() { with(this) { return _c('div', [ _c('test') ]) }}这个_c就是创建VNode的入口,也就是实际上的_createElement函数function _createElement( co

2020-09-17 08:31:20 552

原创 Vue Component原理分析

Component的创建主要分为了两个流程创建组件VNode挂载组件DOM<div> <test></test></div>上面这个页面被解析成了一个渲染函数function() { with(this) { return _c('div', [ _c('test') ]) }}以上渲染函数执行得到模板对应的VNode,得到VNode之后,就会根据VNode

2020-09-17 07:41:08 1224

原创 Vue VNode原理分析

1. VNode是什么及其作用使用js对象来描述真是DOM,把DOM的标签,属性,内容都变成对象的属性。模板编译整个过程就是将template描述成VNode,经过一系列操作形成真实DOM,它的好处有两点兼容性强,不受执行环境的影响。VNode因为是js对象,不管是Node环境还是浏览器环境,都可以统一操作,从而获得了SSR,原生渲染等能力减少DOM操作,任何页面的变化,都是用VNode进行操作对比,只需要在最后一步挂载更新DOM即可2. VNode如何生成Vue内部,有一个专门的VNode类

2020-09-16 18:15:14 1886 2

原创 Vue依赖更新原理分析

依赖更新分为两步修改属性值通知之前收集到的依赖,进行更新dep主要用来存储依赖var Dep = function() { this.subs = [];}Dep.prototype.notify = function() { var subs = this.subs.slice(); for (var i = 0; i < subs.length; i++) { // 遍历依赖存储器,然后一个个调用`watcher.update`

2020-09-16 15:47:16 551

原创 Vue 依赖收集 引用数据类型原理分析

如果数据是引用数据类型,需要对数据进行额外的处理,处理分为对象和数组两种1. 对象每个对象处理之后,会添加一个__ob__的属性, __ob__下面有一个dep属性,dep就是存储watcher的地方。为什么引用类型不能使用dep,因为dep只存在于defineReactive这个函数中,作为一个闭包形式的存在,__ob__.dep在Vue.prototype.$set和Vue.prototype.$delete中都有使用到。2. 数组对数组而言,__ob__.dep的作用是用于对数组相关方法的重

2020-09-16 15:20:29 282

原创 Vue依赖收集基础数据类型

1. 数据初始化流程function initData(vm) { var data = vm.$options.data; data = typeof data === 'function' ? data.call(vm, vm) : data || {}; new Observer(data);}function Observer(data) { var keys = Object.keys(value); for (let i = 0;

2020-09-16 11:19:19 313

原创 Vue模板挂载到页面原理分析

Vue模板挂载到页面可以分为两大部分init和mount1. initVue.prototype._init = function() { // 初始化选项,computed data // 初始化实例,给实例绑定方法 // 触发beforeCreated created钩子}2. mount上面介绍的_init方法中,会有一个挂在到dom的方法if (vm.$options.el) { vm.$mount(vm.$options.el);}``不是所有

2020-09-16 08:13:17 649

原创 Vue selected原理分析

1. Vue是如何设置selectedIndexVue中有一个专门的setSelected来设置这个selectedIndexfunction setSelected(el, binding, vm) { var selected, option; for (var i = 0, l = el.options.length; i < l; i++) { option = el.options[i]; if (isMultiple)

2020-09-15 17:12:54 726

原创 Vue input原理分析

1.input与输入延迟更新先来看Vue给input正常绑定的回调input: function($event) { // 这里就是延迟更新的重点 // 当composing=true时,事件回调不会走到下面的更新操作 if ($event.target.composing) return; name = $event.target.value;}Vue会给input和textarea绑定以下事件compositionstartcompositionendc

2020-09-15 11:54:29 643

原创 Vue 表单元素绑定原理分析

1.v-model指令处理// 这个el是ast, 使用树的结构来表示某个dom节点,包含了绑定的事件,指令,绑定的属性等function model(el, dir) { var value = dir.value; var tag = el.tag; var type = el.attrsMap.type; if (tag === 'select') { genSelect(el, value); } else if (tag === 'inp

2020-09-15 10:42:53 252

原创 v-model原理分析一

VModel双向绑定分为两个部分的内容初始化绑定:初始化时给表单绑定值,绑定事件,为双向更新做准备双向更新:任意一边发生变化,同时能让另一边更新1. v-model怎么给表单绑定数据v-model绑定的数据赋值给表单元素的value属性解析不同的表单元素,配置相对应的事件名和回调,在插入DOM之前,通过addEventListener绑定事件外部变化,触发事件回调,event.target.value赋值给model绑定的数据内部变化,修改表单元素的value下面来看看普通input

2020-09-14 21:52:37 1841

原创 Vue生命周期原理分析

1. 生命周期钩子是如何触发vm中由于mixin存在,可能会存在很多个同类别的声明周期钩子,Vue内部会将这些生命周期的钩子合并。vm.$options.created = [fn, fn, ...];Vue中也初始化了一些标记位,用来表示相关的生命周期钩子是否已经触发function initLifecycle(vm) { vm._isMounted = false; vm._isDestoryed = false; vm.isBeingDestroyed = false

2020-09-14 19:48:40 1208

原创 Vue作用域slot原理分析

<!-- 场景设置 --><!-- 父组件 --><div> <test> <template slot-scope="slotProps"> 我是放在组件的slot: {{slotProps}} </template> </test></div><!-- 子组件 --><main> 我在子组件里面

2020-09-14 17:40:09 403

原创 Vue普通插槽原理分析

1.插槽内容怎么解析的<!-- 场景设置 --><!-- 父组件 --><div> <test>我是放在组件中的slot: {{name}}</test></div>data() { return { name: 11 };}<!-- 子组件 --><main> 我在子组件中 <slot></slot></main>插槽的作

2020-09-14 16:31:38 500

原创 Vue slot原理分析一

Vue中插槽可以分为两种普通插槽,就是不给名字的默认插槽和具名插槽作用域插槽,就是使用子作用域数据的插槽1.普通插槽<!-- 场景设置 --><!-- 父组件 --><div> <test>我是slot中的内容</test></div><!-- 子组件:test --><main> 我在子组件中 <slot></slot></main&

2020-09-14 11:57:09 748

原创 Vue mixin 原理分析二

1.mixin什么时候开始合并合并分为两种1.1 全局mixin和基础全局options合并Vue.mixin = function(mixin) { this.options = mergeOptions(this.options, mixin); return this;}其中基础全局options就是指components, directives, filters, 这3者一开始就挂载到了Vue.options上,所以这三个是最先存在的全局options1.2 全局opt

2020-09-14 08:40:16 244

原创 Vue mixin原理分析

Vue在创建组件实例化之前,会将全局选项和组件选项合并起来,比如全局component, filter, directive, mixin。也就是说我们全局注册的选项会被引入到每个组件中,这样全局选项和组件选项就可以合并起来,之后在组件中就可以访问到全局选项。比如全局过滤器等。为了保证全局选项不被污染,但是又不可能每个组件都深度克隆一遍,这样会导致全局选项的开销过大。如何合并mixin组件合并组件选项和全局选项的优先级组件选项组件mixin组件mixin的mixin组件mixin的…的mix

2020-09-13 20:27:31 936

原创 Vue中directive原理分析二

1. Vue怎么获取到设置的指令钩子以下面一段Vue模板为例<div v-test v-test2></div>以上的模板会被编译成渲染函数with(this) { return _c('div', { directives: [{ name: 'test', rawName: 'v-test' }, { name: 'test2', ra

2020-09-13 15:51:50 577

原创 Vue中directive原理分析

Vue在处理指令时,会首先判断指令是新的还是旧的。也就是需要对比旧节点和新节点上的指令。比如新节点比旧节点上多了一个指令。// 新节点上指令如下newDirectives = { 'v-test': { name: 'test', rawName: 'v-test', }, 'v-test2': { name: 'test2', rawName: 'v-test2' }}// 旧节点上指令如下newDi

2020-09-13 11:48:59 679

原创 Vue中filter原理分析

1. 页面的filter被解析成什么页面中的渲染函数会被生成如下的渲染函数// <div>{{ parentName | all }}</div>(function() { with(this) { return _c('div',[ _v(_s(_f("all")(parentName))) ]) }

2020-09-12 20:56:45 539

原创 Vue中methods原理分析

1. methods是如何绑定this的methods绑定上下文执行环境是通过bind来进行的。固定了这个this。Vue考虑到不是所有的浏览器都支持bind。于是也实现了自己的polyfillBindfunction polyfillBind(fn, ctx) { return function boundFn(a) { const l = arguments.length; return l > 0 ? ( l > 1 ? fn.apply(c

2020-09-12 11:55:33 820

原创 Vue中watch原理分析

Vue中Watch的初始化流程initWatch遍历watch中的每一个watch函数,执行createWatcher,createWatcher有两个作用:获取到watch监听的回调和调用vm.$watch执行vm.$watch,这个函数主要也是两个功能,判断是否是立即执行的监听回调,如果需要立即执行,那就将回调(也就是watch的handler)立即执行一遍。第二个功能是给每一个watch分配一个Watcher。主要来分析一下,新建这个Watcher的过程都做了些什么。var Watche

2020-09-11 17:07:21 574

原创 Vue中Watcher用法分析

Watch在一开始初始化的时候,会读取一次监听的数据的值。于是,这个值就收集到了Watch的watcher。而我们给Watch设置的handler,Watch会放入watcher中。当数据改变时,通知Watch的watcher进行更新,也是handler就被调用了。如果我们设置了immediate: true,就不需要在数据变化时才触发,而是完成初始化之后,就立即执行一次handler。如果我们设置了deep: true,如果被监听的值是对象,Vue会进行深度遍历。这个对象之下的每一个属性都会收集到这个

2020-09-11 16:32:16 1801

原创 Vue中computed原理分析

1.Computed也是响应式的Computed是响应式的,读取Computed会触发get,设置Computed会触发set2.Computed如何控制缓存计算属性是有缓存的,比如某个计算属性C,它依赖data中的A,如果没有缓存的话,每次读取C时,C都回去读取A,从而触发A的get。多次触发A的get有时候是一个非常消耗性能的操作。所以Computed必须要有缓存。computed里面控制缓存最重要的一点就是脏数据标记为dirty, dirty是watcher的一个属性。当dirty为tru

2020-09-10 14:40:24 3846 1

原创 Vue父组件向子组件传递props过程分析二

props也和data一样做了一层代理,实际上的props时挂载到_props上的function proxy(target, sourceKey, key) { Object.defineProperty(taget, key, { get() { return target[sourceKey][key]; }, set(val) { target[sourceKey][key] = val;

2020-09-10 08:24:32 188

原创 Vue父组件向子组件传递props过程分析一

假设我们有以下Vue代码<div> <child-component :name="name" /></div><script>export default { data() { return { name: 'lznism' } }}</script>父组件中包含一个子组件child-component,要弄清楚父组件如何想子组件传递props,首先必

2020-09-09 19:21:11 224

原创 Vue初始化data流程

初始化data流程如下将data中的属性,挂载到实例vm下的_data属性。如果data是函数,会首先对data函数求值对vm._data做代理工作。遍历_data中的每一个key执行proxy(vm, '_data', key)核心proxy的代码如下function proxy(target, sourceKey, key) { Object.defineProperty(target, key, { get() { return this[s

2020-09-09 10:48:13 948 1

原创 Vue响应式原理

Vue响应式原理的核心内容是依赖收集和依赖更新。而以上两个功能是使用Object.defineProperty()来实现的,Object.defineProperty()使用其get和set方法实现依赖收集和依赖更新的。Object.defineProperty(obj, property, { get() { // 依赖收集 }, set() { // 依赖更新 }});依赖在Vue内部是一个数组,该数组里面保存一个个的Watcher

2020-09-09 10:11:38 87

转载 线程和进程的区别

做个简单的比喻:进程=火车,线程=车厢线程在进程下行进(单纯的车厢无法运行)一个进程可以包含多个线程(一辆火车可以有多个车厢)不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)进程可以拓展到多机,进程最多

2020-09-08 11:24:17 219

原创 webpack中splitChunks

splitChunks中chunks总共有3中类型的取值,这也是整个splitChunks的核心所在all 不管文件是动态引入还是非动态引入,统一将文件分离。当页面首次载入会引入所有的包async 将异步加载的文件分离,首次一般不引入,当页面加载时,需要这个组件了才会引入initial 将异步和非异步文件分离,如果一个文件被异步引入也被同步引入,那它会被打包两次,用于分离页面首次需要加载的包...

2020-09-08 10:38:54 2427 1

原创 webpack打包体积优化

1. 引入webpack-bundle-analyzer分析打包后的文件这个插件可以直观展示打包之后,每个包的大小,分析出是否重复打包了某个模块。2. externals项目中我们通过CDN引入了某个库,但是又不想这个库被打包到webpack最终模块中,我们可以使用externalsexternals: { jquery: 'jQuery'}3. tree-shakingwebpack4中production模式下会自动开启tree-shaking模式,但是想要其生效,代码必须是ES

2020-09-07 16:03:57 243

原创 webpack性能优化-提升构建速度

1. 合理配置mode和devtool参数mode可以设置为development和production, 默认为production, 而production下默认会开启tree shaking。此时打包的速度会变慢。2. 缩小文件的搜索范围webpack打包时,如果你的代码中import或者require了别的模块或者第三方库,webpack会按照一定的规则去搜索这些模块。aliasinclude/excludenoParse 告诉webpack不去解析noParse模块所依赖的库ext

2020-09-07 15:47:23 651

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除