面试常见
# 面试常见
# 1.移动端适配
首先是vh、vw,然后用淘宝出品的 lib-flexible 库进行 rem 适配,还有一种 flex + px 的适配方式
主流方案:postcss-px-to-viewport,将px单位转换为vw、vh
# 操作流程:
- npm install postcss-px-to-viewport --save-dev
- 在根目录新建一个名为postcss.config.js的文件
//postcss.config.js
module.exports = {
plugins: {
'postcss-px-to-viewport': {
unitToConvert: "px", // 要转化的单位
viewportWidth: 375, // UI设计稿的宽度
unitPrecision: 6, // 转换后的精度,即小数点位数
propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw selectorBlackList: ["wrap"], // 指定不转换为视窗单位的类名,
minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
replace: true, // 是否转换后直接更换属性值
exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
值得注意的是:postcss-px-to-viewport 同样存在第三方组件库兼容性的问题。比如在设计稿为750px时使用vant组件库会将vant组件的样式缩小
# 解决第三方组件库兼容性的问题
- vant组件库的设计稿是按照375px来开发的。因此在viewportWidth为750px时会出现转换问题
module.exports = ({ webpack }) => {
const viewWidth = webpack.resourcePath.includes(path.join('node_modules', 'vant')) ? 375 : 750;
return {
plugins: {
autoprefixer: {},
"postcss-px-to-viewport": {
unitToConvert: "px",
viewportWidth: viewWidth,
unitPrecision: 6,
propList: ["*"],
viewportUnit: "vw",
fontViewportUnit: "vw",
selectorBlackList: [],
minPixelValue: 1,
mediaQuery: true,
exclude: [],
landscape: false
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
如果读取的node_modules中的文件是vant,那么就将设计稿变为375px。如果读取的文件不是vant的文件,那么就将设计稿变为750px。这样就可以避免vant组件在750px下出现样式缩小的问题了
同理 这对于其他的移动端UI组件库同样有效果。我们只需要改动这行代码即可
const viewWidth = webpack.resourcePath.includes(path.join('node_modules', 'vant')) ? 375 : 750;
1
# 2.Vue 的源码,说说 computed 属性为什么能够在依赖改变的时候,自己发生变化?
- computed 和 watch 公用一个
Watcher
类,在 computed 的情况下有一个 dep收集依赖
,从而达到更新computed属性的效果 - Vue 在二次收集依赖时用
cleanupDeps
卸载一些无用的 dep
# 3.你觉得你的优势是什么?
- 深度思考的能力
- 善于分享
- 社区影响力
# 4.从输入 URL 到页面渲染经历了什么?
- DNS 解析过程,HTML
词法分析
和语法分析,CSS解析
,合成
图层、合成线程调用光栅化线程池,生成位图
后浏览器进程间通信过程,显卡缓存与显示器的关系
# 5.webpack首屏性能优化,由6s多到100ms,我干了啥?
文件大小24M到500kb
- 生产环境关闭
productionSourceMap
、css sourceMap
SourceMap就是当页面出现某些错误,能够定位到具体的某一行代码,SourceMap就是帮你建立这个映射关系的,方便代码调试
const isProduction = process.env.NODE_ENV === 'production'
// 判断是否是生产环境
module.exports = {
productionSourceMap: !isProduction, //关闭生产环境下的SourceMap映射文件
css: {
sourceMap: !isProduction, // css sourceMap 配置
loaderOptions: {
...其它代码
}
},
...其它代码
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 分析大文件,找出源头,npm install
webpack-bundle-analyzer
-D - 必须要用的第三方js通过cdn的方式引用-elementui、echarts是必须使用的,打包又耗时且页面加载也较慢得很。可以通过cdn直接引入,方便且速度快。
// vue.config.js 配置
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
...其它
configureWebpack: [
plugins: [
new BundleAnalyzerPlugin() // 分析打包大小使用默认配置
]
},
...其它
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 使用antd部分加载-npm install babel-plugin-import -D
// main.js
import { Steps } from 'ant-design-vue';
Vue.component(Steps.name, Steps);
Vue.component(Steps.Step.name, Steps.Step);
// babel.config.js
module.exports = {
presets: [ '@vue/cli-plugin-babel/preset' ],
//以下是按需加载的配置++++
plugins: [
[
"import",
{
libraryName: "ant-design-vue",
libraryDirectory: "es",
style: true
}
]
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 使用cdn加载第三方js,BootCDN
- 注意,一定要选择自己项目对应的版本,否则会出现各种奇怪的问题
// 第一步:配置vue.config.js,让webpack不打包这些js,而是通过script标签加入
const isProduction = process.env.NODE_ENV === 'production' // 判断是否是生产环境
//正式环境不打包公共js
let externals = {}
//储存cdn的文件
let cdn = {
css: [
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.0/theme-chalk/index.min.css' // element-ui css 样式表
],
js: []
}
//正式环境才需要
if (isProduction) {
externals = { //排除打包的js
vue: 'Vue',
'element-ui': 'ELEMENT',
echarts: 'echarts',
}
cdn.js = [
'https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js', // vuejs
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.6.0/index.js', // element-ui js
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.6.0/locale/zh-CN.min.js',
'https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.min.js',
]
}
module.exports = {
//...其它配置
configureWebpack: {
//常用的公共js 排除掉,不打包 而是在index添加cdn,
externals,
//...其它配置
},
chainWebpack: config => {
//...其它配置
// 注入cdn变量 (打包时会执行)
config.plugin('html').tap(args => {
args[0].cdn = cdn // 配置cdn给插件
return args
})
}
//...其它配置
}
// 第二步:html模板中加入定义好的cdn变量使用的代码
// index.html中
<!-- 引入样式 -->
<% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%=css%>" >
<% } %>
<!-- 引入JS -->
<% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%=js%>"></script>
<% } %>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
- 按需懒加载
import Table2Excel from "table2excel.js"
download(){
//使用import().then()方式
import("table2excel.js").then((Table2Excel) => {
new Table2Excel.default("#table").export('filename') //多了一层default
})
}
1
2
3
4
5
6
7
2
3
4
5
6
7
- moment.js的优化
- 自己实现一个format方法,或者使用只有6kb的day.js
- 不替换,把moment变得瘦小一些即可,删除掉除中文以外的语言包
chainWebpack: config => {
config.plugin('ignore')
//忽略/moment/locale下的所有文件
.use(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/))
}
// main.js
import moment from 'moment' //手动引入所需要的语言包
import 'moment/locale/zh-cn'; // 指定使用的语言
moment.locale('zh-cn');
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 通过 compression-webpack-plugin 插件把代码压缩为gzip
//打包压缩静态文件插件
const CompressionPlugin = require("compression-webpack-plugin")
//...其它配置
module.exports = {
//...其它配置
chainWebpack: config => {
//生产环境开启js\css压缩
if (isProduction) {
config.plugin('compressionPlugin').use(new CompressionPlugin({
test: /\.(js)$/, // 匹配文件名
threshold: 10240, // 对超过10k的数据压缩
minRatio: 0.8,
deleteOriginalAssets: true // 删除源文件
}))
}
}
//...其它配置
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 6.vue双向绑定的原理
- 数据劫持,结合发布订阅模式
- 一对多
- Object.defineProperty()
- new 一个 Vue,监听数据,编译html
- 监听数据时,每个data会生成一个主题对象dep
- 编译html时,数据和节点绑定生成一个订阅者watcher,将自己添加到dep容器中
- 使用dep.notify触发update更新视图
# 7.深浅拷贝
- 数据类型:基本(String, Number, Boolean, Null, Undefined, Symbol--栈)和引用(Object, Array, Function, Regexp, Date)
- 赋值:赋栈中地址,非堆中数据--不会创建新对象
- 浅拷贝:复制对象指针,不复制对象本身,复制空间,共享内存--会创建新对象
- 浅拷贝实现方式:Object.assign(), Array.prototype.concat/slice(),lodash的_.clone,...,jquery的$.extend
- 深拷贝:创造完全一样新对象,不共享内存,新对象修改不影响原对象--会创建新对象
- 深拷贝实现方式:JSON.parse(JSON.stringify()),手写递归(深度优先遍历),lodash的_.cloneDeep
# 8.什么是原型,原型链
- 每个函数都有prototype(原型)属性,这个属性是一个指针,指向原型对象
- 原型链:假设一个原型对象等于另一个类型的实例,另一个类型的原型对象又等于另一个类型的实例。就像这样一层层递进,就构成了实例与原型的链条—通过proto层层向上找,形成链条
- 最顶层的Object对象没有__proto_,它的值是null
# 9.箭头函数和普通函数的区别
- 箭头函数—更简洁—没有自己的this
- 箭头函数中的this的指向在它在定义时一家确定了,之后不会改变—最近的上下文作用域,往上找最近
- 指向箭头函数定义时所处的对象,而不是箭头函数使用时所在的对象,默认使用父级的this
- call()、apply()、bind()等方法不能改变箭头函数中的this指向
- 箭头函数不能作为构造函数使用,没有自己的arguments,没有prototype—不能new
# 10.什么是闭包,以及应用场景
- 闭包—就是个
函数
—定义在一个函数内部的函数 - 应用场景:retuen data返回一个函数,定义成员函数,减少重复,保护作用域,读取函数内部的变量—让变量的值始终保持在内存中—匿名自执行函数,结果缓存
# 11.computed和watch的区别,运用场景
- computed—
计算
属性—重新计算,数据求和,数据处理 - watch—侦听器—数据变化,异步操作,变化更新数据
# 12.水平垂直居中
- 父相对定位,子绝对定位,left,top50%,transform:translate(-50%, -50%) /margin-top,left: -50px(自身宽高一半)
- flex,justify-content和align-items为center
- 父display,子margin:auto
// 法1:
.parent{
position:relative;
}
.child{
position:absolute;
left:50%;
top:50%;
transform: translate(-50%,-50%); /margin-top,left: -50px(自身宽高一半)
}
// 法2
.parent{
display:flex;
justify-content:center;
align-items:center;
}
// 法3
.parent{
display:flex;
}
.child{
margin:auto;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 13.检测数据类型哪几种,数组怎么判断
- typeof—数组,对象,null会被判断为Object
- instanceof—只能判断引用类型,如数组
- constructor—2个作用 一是判断数据的类型,二是对象实例通过constructor对象访问它的构造函数。需要注意的事情是如果创建一个对象来改变它的原型,constructor就不能来判断数据类型了
- Object.prototype.toString.call()
# 14.data为什么是一个函数,而不是一个对象
- JavaScript中的对象是引用类型的数据,当多个实例引用同一个对象时,只要一个实例对这个对象进行操作,其他实例中的数据也会发生变化
- 在Vue中,我们更多的是想要复用组件,那就需要每个组件都有自己的数据,这样组件之间才不会相互干扰—所以组件的数据不能写成对象的形式,而是要写成函数的形式—对象变,复用的都变了
- 据以函数返回值的形式定义,这样当我们每次复用组件的时候,就会返回一个新的data,也就是说每个组件都有自己的私有数据空间,它们各自维护自己的数据,不会干扰其他组件的正常运行—闭包的使用—柯里化了
# 15.v-for循环key的作用
- 用唯一标识标记每个节点,
高效渲染
虚拟Dom树,避免index重复
造成渲染错误
# 16.Vue2为何重写数组方法,如何重写
- vue响应式的Object.defineProperty(),没办法监听数组长度的变化,没办法监听数组的新增
- vue无法检测通过数组索引改变数组的操作,尤大认为性能消耗与用户体验不成正比,对数组进行响应式检测会带来很大的性能消耗,因为数组项可能会大
- 如何重写:ob.dep.notify—覆盖数组原有的原型对象—arr.proto = Object.create( Array.prototype)
# 17.http常见状态码
- 200--成功
- 301--永久重定向, 302--临时重定向, 304--未修改
- 403--服务器拒绝请求,404--找不到,服务端找不到请求的网页
- 500--服务器内部错误
# 18.说一下防抖和节流--setTimeout
- 防抖--公交,每次上人重新,再等5分钟
- 节流--地铁,每5分钟一趟,不等人
# 19.vue的常用指令集
- v-if:js的dom,更高的切换开销
- v-show:css的display,频繁切换更合适,更高的初始渲染开销
- v-on:click = @click,事件绑定,修饰符,.stop阻止事件冒泡,.prevent阻止默认行为
- v-bind:动态属性
- v-for:列表渲染,数组对象
- v-html:解析并插入html标签
- v-model:获取表单控件的值,input等,双向绑定,修饰符,.number,以parseFloat转成数字类型,.trim,去除首尾空白字符
# 20.css的优先级
!important > 内联sytle > id > class > 元素div > *(通配符)
# 21.盒子模型
- w3c: box-sizing: content-box; 元素宽高 = 内容大小
- ie: box-sizing: border-box; 元素宽高 = 内容大小 + 内边距padding + 边框大小border
# 22.css实现左右固定宽度,中间自适应
- 法1:浮动,左左浮动,中右右浮动,左右指定宽度,中间宽度为100%
- 法2:父display: flex,flex-direcrion: row,子左右指定宽度,中间设置flex:1
- 法3:用calc计算中间属性:中间宽度:calc(100% - 左侧宽度 - 右侧宽度)
# 23.git常见指令
- 查看当前状态:git status
- 添加文件到栈:git add .
- 提交文件:git commit
- 推送文件到远端:git push origin master(分支名)
- 查看历史记录:git log
# 24.spa单页面,优缺点?
- 优点:体验好,适配多端,
减轻服务端压力
,前后端分离 - 缺点:首屏加载慢,不利于seo
# 25.说一下vue3.0常用属性
- setup,只能是同步,return
- ref,对原始数据的拷贝
- reactive,响应式数据对象
- toRef(),响应式数据单个
- toRefs(),响应式数据多个
# 26.setTimeout和this.$nextTick()那个先执行,为什么?
- this.$nextTick()先执行,页面更新完毕后执行,异步的更新队列
- 顺序:Promise.resolve().then > watch > this.$nextTick > setTimeout > process.nextTick
- 原因:两者回调执行条件不一样,this.$nextTick这个方法是同步,但内部的方法会异步执行
# 27.常见行内元素
- 行内元素:不换行,不能设置宽高,span,a,i,b
- 块级元素:换行,div,ul,li,h1-6,转行内块dispaly : inline-block
- 行内块元素:不换行,能设置宽高img,input,select,button
# 28.重绘和回流
- 重绘:样式css,颜色改变
- 回流:布局,js和css修改
- 回流必然引起重绘
# 29.服务端渲染
- ssr,同构直出
- 利于首屏渲染,体验好,利于seo
- 加大服务器压力,学习成本高
# 30.linux常见指令
- 文件软链接关联:sudo ln -s 路径1 路径2
- 查看文件:ls
- 打开文件:cat 文件路径名称
- 删除文件:rm -rf 文件路径名称
- 进入文件:cd
- 解压文件:tar -zxvf xxx.tar.gz 解压缩 xxx.tar.gz
- 压缩文件:tar -zcvf xxx.tar.gz aaa bbb 压缩aaa bbb目录为xxx.tar.gz
- 显示文件最后10行:tail -n 10
# 31.说一下react的hooks
- Hook 是 React 16.8 的新增特性
- 组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。而React Hooks 就是我们所说的“钩子”
- 纯函数组件没有状态
- 代码简洁,更易于复用
- 通过
单链表
来管理Hooks,挂载到fiberNode上 - useState,私有状态
- useEffect,接口请求,watch,mount的监听,异步完成
- useLayoutEffect,同步,之前先执行,componentDidMount,DOM操作
- useRef,获取dom,ref.current.value
- useContent,跨2层组件传值
- useMemo,computed,值
- useCallback,函数
- useHistory,路由跳转,useHistory().push('/gateway-agent/operation-data/edit?id=' + record.id)
- useLocation,路由跳转参数获取,获取useLocation().query.id
# 32.react的更新机制
- 新旧dom树,进行diff
- 同层节点之间相互比较,不跨节点
- 发现不同直接跳出比较
- 不同类型的节点,产生不同的树结构:如果该节点不同,会将旧tree中该节点的子树全部删掉。直接生成新的子树,挂载到DOM中
- 开发中,可以通过key来指定哪些节点在不同的渲染下保持稳定
# 33.redux 里面有什么
- state:初始状态
- action:视图发出的通知
- reducer:纯函数,state的计算过程
- store:状态容器
- 用dispatch通过派发action更新state,action派发后,内部有两个事情处理,一是要调用reducer更新state,二是触发之前订阅过的事件执行,就完了
- 流程图
# 34.react和vue框架的区别
- react,中大型项目,vue简单快速,小型项目
- react严格讲mvc的view层,vue为mvvm
- react,state不可变,vue,data可变
- react单向数据流,vue双向绑定
- React 默认是通过比较引用的方式进行的,Vue 通过 getter/setter 以及一些函数的劫持
- React 是通过JSX渲染模板,Vue是通过一种拓展的HTML语法进行渲染
- React 的做法是 JSX + inline style,vue的是使用 webpack + vue-loader 的单文件组件格式
# 35.优雅降级和渐进增强
- 优雅降级:保证低级浏览器也有基本功能就好,以高要求,高版本为基准,向下兼容
- 渐进增强:开始针对低版本的浏览器构建页面,满足最基本的功能,再针对高级浏 览器进行效果,交互,追加各种功能,向上兼容
- -webkit-兼容css,实现渐进增强
# 36.标准文档流
- 元素排版,自动从左往右,从上往下的流式排列方式,最终窗体自上而下分成一行行,并在每行中从左至右的顺序排放元素
# 37.mvvm框架是什么?和jquery的区别,那些场景适合?
- mvvm:是Model-View-ViewModel(视图模型)的简写,数据的双向绑定
- 区别jquery:使用选择器($)选取DOM对象,并对其进行赋值、取值、事件绑定等操作,主要是操作DOM
- vue不在引用相应的DOM对象,通过vue对象,将数据和相应的DOM对象相互绑定起来
- 适合场景:vue复杂数据操作的后台页面,表单填写页面--数据绑定
- jquery适用的场景:比如说一些html5的动画页面,一些需要js来操作页面样式的页面--样式操作,动画效果
# 38.如何判断是promise对象
- Object.prototype.toString.call()
- 如果一个变量是 Object, 有 then 和 catch 方法, 就认为是 Promise
const isPromise = (val) => {
return isObject(val) && isFunction(val.then) && isFunction(val.catch);
};
1
2
3
2
3
- node中可以使用 util.types.isPromise
- result instanceof Promise--只能判断 es6 标准的 promise 实例,无法判断 Bluebird 等的第三方 promise 实现
- 第三方库不是 new Promise 实现的,而是返回了自己构造的一个类,就是一个符合 Promise A+ 标准的类实例
- Bluebird ,比原生 Promise 强大,一个第三方 Promise 规范实现库
# 39.es6和7
- es6--let,const,箭头函数,解构赋值,...,sort,map,reduce,filter,forEach,concat,字符串拼接,class,promise,模块化import
- es7--async/await
# 40.实现通用网格布局
- display: grid
- 默认情况下,容器元素都是块级元素
- grid-template-columns:列宽
- grid-template-rows:行高
- repeat,重复次数,grid-template-columns: repeat(3, 33.33%),重复3次 33.33%
- auto-fill,自动填充,grid-template-columns: repeat(auto-fill, 100px)
- vue-grid-layout,响应式栅格
- grid-column,grid-row设置每一项的宽高
# 41.如何让一个对象属性值,不发生改变?
- 冻结对象—Object.freeze(obj)