typeof 与intanceof的区别
typeof和instanceof的区别是:typeof的返回值是一个字符串,用来说明变量的数据类型;instanceof的返回值是布尔值,用于判断一个变量是否属于某个对象的实例。
typeof 一般只能返回如下几个结果: number, boolean, string, function, object, undefined。
对于 Array, Null 等特殊对象使用 typeof 一律返回 object, 这正是 typeof 的局限性。
instanceof:
1、返回值为布尔值
2、instanceof 用于判断一个变量是否属于某个对象的实例。
BFC的布局规则
内部的Box会在垂直方向,一个接一个地放置。
Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。
每个盒子(块盒与行盒)的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
BFC的区域不会与float box重叠。
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
计算BFC的高度时,浮动元素也参与计算
Webpack 性能如何优化,有过什么优化的方案和结果,说了下自己的方案啥的
1).压缩、合并文件
压缩文件 -> 减少HTTP请求大小,可以减少请求时间
文件合并 -> 减少HTTP请求数量。
我们可以对html、css、js以及图片资源进行压缩处理,现在可以很方便的使用 webpack 实现文件的压缩:
js压缩:UglifyPlugin
CSS压缩:MiniCssExtractPlugin
HTML压缩:HtmlWebpackPlugin
图片压缩:image-webpack-loader
2)提取公共代码
合并文件虽然能减少HTTP请求数量, 但是并不是文件合并越多越好,还可以考虑按需加载方式(后面第6点有讲到)。什么样的文件可以合并呢?可以提取项目中多次使用到的公共代码进行提取,打包成公共模块。
可以使用 webpack4 的splitChunk插件cacheGroups选项。
3)按需加载
这时候就可以使用按需加载, 将每个路由页面单独打包为一个文件,当然不仅仅是路由可以按需加载。
根据文件内容生成文件名,结合 import 动态引入组件实现按需加载:
通过配置 output 的 filename 属性可以实现这个需求。filename 属性的值选项中有一个[contenthash],它将根据文件内容创建出唯一 hash。当文件内容发生变化时,[contenthash]也会发生变化。
output: {
filename:'[name].[contenthash].js',
chunkFilename:'[name].[contenthash].js',
path: path.resolve(__dirname,'../dist'),
},
4)减少冗余代码
一方面避免不必要的转义:babel-loader用 include 或 exclude 来帮我们避免不必要的转译,不转译node_moudules中的js文件,其次在缓存当前转译的js文件,
设置loader: 'babel-loader?cacheDirectory=true'
其次减少ES6 转为 ES5 的冗余代码:Babel 转化后的代码想要实现和原来代码一样的功能需要借助一些帮助函数,比如:
如果在很多文件里都声明了类,那么就会产生很多个这样的helper函数。
这里的@babel/runtime包就声明了所有需要用到的帮助函数,而@babel/plugin-transform-runtime的作用就是将所有需要helper函数的文件,从@babel/runtime包 引进来:
如果在很多文件里都声明了类,那么就会产生很多个这样的helper函数。
这里的@babel/runtime包就声明了所有需要用到的帮助函数,而@babel/plugin-transform-runtime的作用就是将所有需要helper函数的文件,从@babel/runtime包 引进来:
5).服务器端渲染
客户端渲染: 获取 HTML 文件,根据需要下载 JavaScript 文件,运行文件,生成 DOM,再渲染。
服务端渲染:服务端返回 HTML 文件,客户端只需解析 HTML。
优点:首屏渲染快,SEO 好。缺点:配置麻烦,增加了服务器的计算压力
webpack里面的loader 和 plugin 区别
* loader是文件加载器,能够加载资源文件,并对文件进行一些处理,如编译,压缩 等,最终一起打包到指定的文件中。
* plugin赋予了webpack各种灵活的功能,如打包优化,资源管理,环境变量,注入等,目的是为了解决loader无法实现的功能。
从整体的运行机制上来看,如下图所示:

* loader运行在项目打包之前;
* plugins运行在整个项目的编译时期;
webpack 的运行流程是一个串行的过程,它的工作流程就是将各个插件串联起来
从启动到结束会依次执行以下三大步骤
1.初始化流程:从配置文件和 Shell 语句中读取与合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数
webpack 将 webpack.config.js 中的各个配置项拷贝到 options 对象中,并加载用户配置的 plugins完成上述步骤之后,则开始初始化Compiler编译对象,该对象掌控者webpack声明周期,不执行具体的任务,只是进行一些调度工作
2,.编译构建流程:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理
初始化完成后会调用Compiler的run来真正启动webpack编译构建流程,主要流程如下:
1.compile 开始编译2.make 从入口点分析模块及其依赖的模块,创建这些模块对象3.build-module 构建模块
4.seal 封装构建结果
5.emit 把各个chunk输出到结果文件
3).输出流程:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到文件系统
keep-alive的原理
组件一旦被 <keep-alive> 缓存,那么再次渲染的时候就不会执行 created、mounted 等钩子函数。使用keepalive组件后,被缓存的组件生命周期会多activated和deactivated 两个钩子函数,它们的执行时机分别是 <keep-alive> 包裹的组件激活时调用和停用时调用。
想要缓存的组件一定要给定name属性,并且要和include,exclude给定的值一致
<keep-alive>组件可以接收三个属性:
include- 字符串或正则表达式。只有名称匹配的组件会被缓存。exclude- 字符串或正则表达式。任何名称匹配的组件都不会被缓存。max- 数字。最多可以缓存多少组件实例
它有created,destroyed,mounted,render四个钩子
created与destroyed钩子
created钩子会创建一个cache对象,用来作为缓存容器,保存vnode节点。
destroyed钩子则在组件被销毁的时候清除cache缓存中的所有组件实例
render钩子:重点来了,keep-alive实现缓存的核心代码就在这个钩子函数里。
1. 先获取到插槽里的内容
2. 调用getFirstComponentChild方法获取第一个子组件,获取到该组件的name,如果有name属性就用name,没有就用tag名。
用获取到的name和传入的include,exclude属性进行匹配,如果匹配不成功,则表示不缓存该组件,直接返回这个组件的 vnode,否则的话走下一步缓存
用拿到的name去this.cache对象中去寻找是否有该值,如果有则表示该组件有缓存,即命中缓存:缓存的处理:
命中缓存时会直接从缓存中拿 vnode 的组件实例,此时重新调整该组件key的顺序,将其从原来的地方删掉并重新放在this.keys中最后一个。
如果没有命中缓存,即该组件还没被缓存过,则以该组件的key为键,组件vnode为值,将其存入this.cache中,并且把key存入this.keys中。此时再判断this.keys中缓存组件的数量是否超过了设置的最大缓存数量值this.max,如果超过了,则把第一个缓存组件删掉。
那么问题来了:为什么要删除第一个缓存组件并且为什么命中缓存了还要调整组件key的顺序?
这其实应用了一个缓存淘汰策略LRU:
mounted钩子
在这个钩子函数里,调用了pruneCache方法,以观测 include 和 exclude 的变化。
如果include 或exclude 发生了变化,即表示定义需要缓存的组件的规则或者不需要缓存的组件的规则发生了变化,那么就执行pruneCache函数,
在该函数内对this.cache对象进行遍历,取出每一项的name值,用其与新的缓存规则进行匹配,如果匹配不上,则表示在新的缓存规则下该组件已经不需要被缓存,则调用pruneCacheEntry函数将其从this.cache对象剔除即可。
网友评论