文章目录
最近在看前端面试题,一直相信自己整理过印象才会更加深刻,对一些知识点的理解不能只停留在表面的1234几点,需要进行扩展。 最近的面试经历更让我了解到自己的不足
changeLog:
9.18 vue问题由7个添加到30个
一.基础
-
新元素
- 语义化标签nav, article, aside, header,footer
- canvas
- Audio、video
- 地理位置
- input校验
-
css新元素
- 选择器
- 动画
- 过渡
- transform
- 弹性盒模型
- 媒体查询 @media
- 渐变 inear-gradients
- 背景
- 边框
-
实现左右固定宽,中间自适应
.wrap { width: 200px; height: 200px; border: 1px solid red; position: relative; } /*1.已知元素高下使用定位+负margin*/ .box1 { background-color: pink; position: absolute; top: 50%; left: 50%; margin-top: -50px; margin-left: -50px; }
-
rem与em区别
rem是根据根的font-size变化, 而em是根据父级的font-size变化
-
css权重
行内1000、id选择器100、类、属性选择器10, 伪类选择器、元素名1
以上面的权重值为基础, 叠加计算权重。
伪类选择器:after, before, first-letter, first-line, selection
- 当同样的元素写多次时,以最下面的为准,即css样式会覆盖
- 与元素‘挨得近’的规则生效, 比如在html中定义了规则,在css中也定义了规则, 则html中的规则生效
/*html中*/ <style type="text/css"> h1 { padding:10px; } </style> /*css中*/ h1 { padding: 5px; }
- 通配符权重为0
- !important权重最高,但也会被权重更高的!important覆盖
es6
- let、const、var的区别
let相当于var,用于声明变量,在块级作用域内有效,不能重复声明,不会变量提升,不会预处理
const: 用于定义常量,不可修改,其他特点等同于let, 用于保存不用改变的数据 - map与普通对象的区别
普通对象只能用字符串当作键,而es6中的map数据结构,类似于对象,也是键值对的集合,但是键的范围不限于字符串,各种类型的值(包括对象)都可以当作键 - 常用es6语法
箭头函数,模板字符串、变量解构赋值等
跨域
-
jsonp跨域
通过script标签引入js文件,这个js文件又会返回一个js函数调用,也就是请求后通过callback方式回传结果缺点:只支持get请求
优点:
1.不受同源策略限制
2.兼容性更好
3.支持老版本浏览器 -
cors跨域
使用自定义的http头部请求。让浏览器与服务器之间进行沟通,从而决定请求或相应是否成功
优点:
1.支持所有类型的http请求
2.比jsonp有更好的错误处理机制
3.被大多数浏览器支持 -
h5的postMessage方法
h5新特性,目前只支持窗口(iframe)之间交换数据, 不能和服务端交换
-
ajax了解
客户端发起请求,获取或发送服务端数据的一项技术
优势
-无刷新页面
-服务器端任务转到客户端处理
-减轻浏览器负担节约带宽
-彻底将页面与数据分离缺点
-无法使用回退按钮
-不利于网页seo
-不能发送跨域请求 -
闭包
嵌套函数引用了外部函数变量的函数叫做闭包。可能会造成变量污染 -
window.location对象包括哪些属性
hash、host、hostname、href、origin、pathname、search、protocol
-
手写ajax实现过程
-
轮播图实现原理概述
一系列的大小相等的图片平铺,利用CSS布局只显示一张图片,其余隐藏。通过计算偏移量利用定时器实现自动播放,或通过手动点击事件切换图片
-
this的指向
this永远指向最后调用它的那个对象
Tips:改变this指向的方法:
- 使用es6的箭头函数,箭头函数的this始终指向函数定义时的this、而非执行时
- 函数内部使用_this=this
- 使用apply、call、bind
- new实例化一个对象
-
严格模式
引自阮一峰老师博客详解严格模式
严格模式是ES5中提出的运行模式,其目的为下面几个
- 消除js语法的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的不安全之处,保证代码运行安全
- 提高编译器效率,增加运行速度
- 为未来新版本的js做好铺垫
调用:
<script>
"use strict"; // 必须放在第一行
</script>
// 针对函数
function strict(){
"use strict";
return "这是严格模式"
}
规定:
- 全局变量必须显示声明
- 禁止使用with语句
- 创设eval作用域。正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部。
"use strict";
var x = 2;
console.info(eval("var x = 5; x")); // 5
console.info(x); // 2
- 禁止this关键字指向全局对象
- 禁止在函数内部遍历调用栈
- 禁止删除变量,只有configurable设置为true的对象属性,才能被删除
"use strict";
var x;
delete x; // 语法错误
var o = Object.create(null, {'x': {
value: 1,
configurable: true
}});
delete o.x; // 删除成功
- 对一个对象只读属性赋值报错
- 对一个getter方法读取的属性赋值报错
- 对禁止扩展的对象添加新属性报错
- 删除不可删除的属性报错
- 对象不能有重名属性
- 函数不能有重名参数
- 禁止八进制表示法 如
var n=0100;
- 不允许对arguments赋值;
- arguments不再追踪参数变化
function f(a) {
a = 2;
return [a, arguments[0]];
}
f(1); // 正常模式为[2,2]
function f(a) {
"use strict";
a = 2;
return [a, arguments[0]];
}
f(1); // 严格模式为[2,1]
- 禁止使用arguments.callee
- 函数必须声明在顶层
- 也就是说,不允许在非函数的代码块内声明函数
-
bind、call、apply区别
apply()方法调用一个函数,其具有一个指定this值,以及作为一个数组(或类似数组的对象)提供的参数
call()方法接受的是若干个参数列表,而apply接收的是一个包含多个参数的数组
bind()方法创建一个新的函数,然后传入this所绑定的值和参数
var a ={ name : "Cherry", fn : function (a,b) { console.log( a + b) } } var b = a.fn; b.apply(a,[1,2]) // 3 b.call(a,1,2) // 3 b.bind(a,1,2)() // 3
二.框架
-
组件传值
-父传子: props
-子传父:on+$emit传递
-父子双向:on.sync
-子孙之间:通过一个中间文件作为媒介,子组件传值到中间文件,父组件从中间文件获取,避免逐级获取
-兄弟:event|vuex -
vue生命周期
创建、挂载、更新、销毁(几个钩子函数)
首先创建实例,执行init,init过程中先调用beforeCreate,然后在injections 和reactivity时,再去调用created,要修改data数据的话最早也得在created里面去做
created完成后,它会判断实例里是否含有el选项,没有的话会调用vm.$mount(el)方法,然后执行下一步,有的话会将模版解析成模版函数来编译模板
render函数是发生在beforeMount和mounted之间的,当执行完render函数后会调用mounted,mounted挂载结束后 实例就算走完流程。
更新和销毁一般是外部触发的
-
常用vue指令
v-if v-show、v-for、v-on、v-bind、v-slot、v-model
-
V-show、v-if区别, 应用场景
v-if是‘真正’的条件渲染,当满足条件时才会销魂和重建
v-show无论初始条件是什么 元素总会被渲染,只是机遇css进行切换
在性能消耗方面: v-if 有更高的切换消耗,v-show有更高的初始渲染消耗
所以,如果需要频繁切换,使用v-show, 如果运行时条件很少改变使用v-if
- 对于管理系统的权限列表来说, 使用v-if会避免渲染不该出现的权限
- 前台页面的数据展示推荐使用v-show
-
vuex原理
vuex是一个状态管理容器, 数据的流向是单向数据流,数据并不具有持久化特性,默认刷新就重置所有状态
里边的数据及方法与vue对比来看
-
vue双向绑定如何实现?用了什么模式
vue数据双向绑定是通过数据劫持结合发布-订阅者模式的方式来实现,
流程图如下:
我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。因此接下去我们执行以下3个步骤,实现数据的双向绑定:
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。 -
vue-router的两种模式主要依赖什么实现?
- hash主要依赖
location.hash
来改动url,达到不刷新跳转的效果,每次hash
改变都会触发hashchange
事件 - history主要利用了h5的historyAPI来实现,用
pushState
和replaceState
来操作浏览历史记录
- hash主要依赖
-
Vue-router有哪几种导航守卫?
- 全局守卫beforeEach beforeResolve、afterEach
- 路由独享守卫 beforeEnter
- 路由组件内守卫 beforeRouteEnter 、 beforeRouteUpdate、 beforeRouteLeave
-
Vue-router的动态路由如何定义?怎样获取传过来的动态参数
在router目录下的index.js文件中,对path属性加上/:id
使用router对象的params.id
-
scss是什么?在vue-cli中安装步骤?有哪些特性
css的预编译
1.用npm下三个loader(sass-loader、css-loader、node-sass)
2.在build目录找到webpack.base.config.js,在extends属性中加一个扩展.scss
3.在同一个文件,配置一个module属性
4.在组件的style标签加上lang属性, 例如 lang=‘scss’
特性:可以用变量、可以嵌套、可以用混合器
-
说说你对SPA单页面的理解,优缺点
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。
优点:
- 用户体验好、快,内容的改变不需要重新加载整个页面,避免不必要的跳转和重复渲染
- SPA相对服务器压力小
- 前后端分离、架构清晰,前端进行交互逻辑,后端负责数据处理
缺点:
- 初次加载耗时多
- 前进后退路由管理,由于单页应用在一个页面中显示所有内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理
- seo难度大
-
Class与style如何动态绑定
可以将属性值抽象出来赋予变量,通过v-bind绑定标签
-
怎样理解Vue的单向数据流
所有的prop都使得其父子prop之间形成了一个单向下行绑定:父级prop的更新会向下流动到子组件中, 但反过来却不行
这样会防止从子组件意外改变父级组件的状态,从而导致你的应用数据流向难以理解
子组件想修改时,只能通过$emit派发一个自定义事件,父组件接收到后,由父组件修改
-
computed和watch的区别和应用场景
computed: 计算属性, 依赖其他属性值,并且computed的值有缓存,只有它依赖的属性值发生改变时,下一次获取computed的值才会重新计算
watch: 更多的是观察作用,类似于某些数据的监听回调,每当监听的数据发生变化时都会执行回调后续操作
场景:
- 当我们需要进行数值计算,并依赖其他数据时,应当使用computed
- 当我们需要在数据变化时执行异步或开销较大操作时,应该使用watch
-
直接给一个数组项赋值,Vue能检测到变化吗
由于js的限制,Vue不能检测到以下数组变动
- 利用索引设置一个数组项
- 修改数组长度
Vue提供了以下操作方法
// Vue.set Vue.set(vm.items, indexOfItem, newValue) // Vue.$set Vue.$set(vm.items, indexOfItem, newValue) // Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue)
为了解决第二个问题,Vue提供了以下操作方法
vm.items.splice(newLength)
-
Vue父子组件生命周期钩子函数执行顺序
加载渲染过程
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
子组件更新过程:
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
父组件更新过程:
父 beforeUpdate -> 父 updated
销毁过程:
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
-
在哪个生命周期内调用异步请求
可以在钩子函数created、beforeMount、mounted中进行调用,因为在这三个钩子函数中,data已经被创建,可以将服务端返回的数据进行赋值,但是更推荐在created钩子函数中调用异步请求,因为在created钩子函数中调用异步请求有以下优点:
- 能更快获取到服务端数据,减少页面loading时间
- ssr不支持beforeMount、mounted钩子函数,保证一致性
-
什么阶段可以访问操作DOM
mounted
-
父组件可以监听到子组件的生命周期吗
可以使用$emit触发父组件的事件,也可以在父组件引用子组件时通过@hook来监听
-
谈谈你对keep-alive的理解
keep-alive是vue内置的一个组件,可以使被包含的组件保留状态,避免重新渲染
有以下特性:
- 一般会结合路由与动态组件一起使用,用于缓存组件
- 提供include和exclude属性。两者都支持字符串和或正则表达式,include表示只有名称匹配的组件会被缓存
- 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated
-
组件中data为什么是一个函数
因为组件是用来复用的,且js中对象是引用关系,如果组件中data是一个对象,那么这样作用域没有隔离,子组件中的data属性值会相互影响
而new Vue的实例,是不会被复用的,因此不存在引用对象的问题
-
v-model的原理
我们在 vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
- text 和 textarea 元素使用 value 属性和 input 事件;
- checkbox 和 radio 使用 checked 属性和 change 事件;
- select 字段将 value 作为 prop 并将 change 作为事件。
以 input 表单元素为例:
<input v-model='something'> 相当于 <input v-bind:value="something" v-on:input="something = $event.target.value">
如果在自定义组件中,v-model 默认会利用名为 value 的 prop 和名为 input 的事件,如下所示:
父组件: <ModelChild v-model="message"></ModelChild> 子组件: <div>{{value}}</div> props:{ value: String }, methods: { test1(){ this.$emit('input', '小红') }, },
-
说说Vue SSR
SSR大致的意思就是vue在客户端将标签渲染成的整个 html 片段的工作在服务端完成,服务端形成的html 片段直接返回给客户端这个过程就叫做服务端渲染。
优点:
- 更好的SEO
- 更快的内容到达时间(首屏加载)
缺点:
- 开发条件限制,例如服务端渲染只支持beforeCreate和created两个钩子函数,会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行
- 更多的服务器负载
-
Vue怎么实现对象和数组的监听
Vue 框架是通过遍历数组 和递归遍历对象,从而达到利用 Object.defineProperty() 也能对对象和数组(部分方法的操作)进行监听。
-
Proxy与Object.defineProperty对比
Proxy 的优势如下:
- Proxy 可以直接监听对象而非属性;
- Proxy 可以直接监听数组的变化;
- Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
- Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
- Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;
Object.defineProperty 的优势如下:
- 兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。
-
Vue 怎么用 vm.$set() 解决对象新增属性不能响应的问题 ?
vm.$set 的实现原理是:
- 如果目标是数组,直接使用数组的 splice 方法触发相应式;
- 如果目标是对象,会先判读属性是否存在、对象是否是响应式,最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理( defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 的功能所调用的方法)
-
虚拟DOM优缺点
优点:
- 保证性能下限
- 无需手动操作DOM
- 跨平台
缺点:
- 无法进行极致优化,在一些性能要求极高的应用中虚拟DOM无法进行针对性的极致优化
-
虚拟Dom实现原理
虚拟 DOM 的实现原理主要包括以下 3 部分:
- 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
- diff 算法 — 比较两棵虚拟 DOM 树的差异;
- pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
-
Vue中的key的作用
key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速。
更准确:因为带 key 就不是就地复用了,在 sameNode 函数
a.key === b.key
对比中可以避免就地复用的情况。所以会更加准确。更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快
-
对Vue项目进行的优化
代码层面的优化
- v-if 和 v-show 区分使用场景
- computed 和 watch 区分使用场景
- v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
- 长列表性能优化
- 事件的销毁
- 图片资源懒加载
- 路由懒加载
- 第三方插件的按需引入
- 优化无限列表性能
- 服务端渲染 SSR or 预渲染
webpack层面优化
- Webpack 对图片进行压缩
- 减少 ES6 转为 ES5 的冗余代码
- 提取公共代码
- 模板预编译
- 提取组件的 CSS
- 优化 SourceMap
- 构建结果输出分析
- Vue 项目的编译优化
基础web技术优化
- 开启 gzip 压缩
- 浏览器缓存
- CDN 的使用
- 使用 Chrome Performance 查找性能瓶颈
三.架构
1.amd/cmd/commonjs差异
目前流行js的模块化规范有amd、cmd、commonjs
- cmd和sea.js: cmd推崇依赖就近,延迟执行, 在需要时声明
- amd和require.js: amd推崇依赖前置,提前执行,先声明后使用
- commonJS用同步的方式加载模块
- es6 module模块功能由两个命令
export
和import
构成
2.commonJS与ES6模块差异
- CommonJS模块输出的是值的拷贝,一旦输出值,模块内部的变化不会影响到这个值。ES6机制是JS引擎静态分析脚本时,遇到
import
,会生成一个只读引用,当脚本执行时,再根据只读引用去模块中取值。因此ES6模块是动态引用,而且不会缓存值
- CommonJS是运行时加载,即输入时先加载整个模块,然后生成一个对象,从这个对象中读取方法
- ES6是编译时加载, 通过export命令显示指定输出的代码, import时可以指定加载某个输出值,而不是加载整个模块
3. Webpack? webpack常见优化手段
webpack是一个资源处理工具,可以对资源打包、解析、区分开发模式
常见优化:
- 分离第三方依赖,比如引入dll
- 引入多进程编译, 比如happypack
- 提取公共的依赖模块
- 资源混淆、压缩
- 分离样式、减小bundle、chunk的大小
- GZIP压缩
4. MVC、MVVM
MVC模式是软件分为三个部分: View\Controller\Model
- 视图View: 用户界面
- 控制器: 业务逻辑
- 模型: 数据保存
1. view传送指令到Controller
2. Controller完成业务逻辑后,要求model改变状态
3. model将新的数据发送到view, 用户得到反馈
所有通信都是单向的
MVVM模式,采用双向绑定,view的变动,自动反映在viewmodel, 反之亦然
MVVM与MVC最大的区别就在于双向绑定
5.BFF架构
Backend For Frontend即后端服务于前端,为不同设备提供不同API
优点:
- 能够满足因不同客户端特殊的交互引起的对新接口的要求,一开始就针对相应设备设计好对应的接口
- 避免多端使用一个接口造成的耦合,或过多无用字段
缺点:
- 代码重复、加大开发工作量
6.PWA
Progressive Web Apps 是 Google 提出的用前沿的 Web 技术为网页提供 App 般使用体验的一系列方案。
四. 网络
1.http请求资源过程
- 查看浏览器中是否有缓存。有的话直接访问缓存
- 如果缓存过期或没有,重新请求
- 发送请求前,域名解析,获取相应ip地址
- 浏览器与服务器发起tcp连接 三次握手
- 握手成功,请求数据包
- 服务器处理请求。返回数据给浏览器
- 浏览器收到http响应
- 读取页面内容,浏览器渲染,解析html源码
2.http状态码
- 1xx, 信息、服务器收到请求。需要请求者继续执行操作
- 2xx, 成功 操作被成功接收并处理
- 3xx 重定向,需要进一步操作完成请求 304缓存 301,302重定向
- 4xx 客户端错误
- 5xx 服务端错误
3.http与https区别
- http超文本传输协议,信息明文传输,安全性低,无状态连接,速度快
- https比http多了个安全证书,采取的连接方式与http不同,由ssl+http协议构建的协议,可进行加密传输、身份认证
4.get与post区别
- 请求参数长度不同,post没有长度限制
- get明文拼接,post通过请求体发送参数、参数不会直接显示