面试常见

# 面试常见

# 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

  值得注意的是: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

  如果读取的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
  • 分析大文件,找出源头,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
  • 使用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
  • 使用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
  • 按需懒加载
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
  • 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
  • 通过 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

# 6.vue双向绑定的原理

  • 数据劫持,结合发布订阅模式
  • 一对多
  • Object.defineProperty()
  • new 一个 Vue,监听数据,编译html
  • 监听数据时,每个data会生成一个主题对象dep
  • 编译html时,数据和节点绑定生成一个订阅者watcher,将自己添加到dep容器中
  • 使用dep.notify触发update更新视图

Image Text

# 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

# 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,二是触发之前订阅过的事件执行,就完了
  • 流程图

Image Text

# 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
  • 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)