前端常见面试题
HTML5部分
HTML5新特性有哪些
- Canvas绘图以及SVG绘图
- 语义化标签(header、nav、footer、article、section)
- 音频、视频(audio、video)API
- 拖放(Drag and drop)API
- 地理定位(Geolocation)
- 本地离线存储(localStorage),长期存储数据,关闭浏览器后不丢失。
- 会话储存(sessionStorage),数据在关闭浏览器后自动删除。
cookie与sessionStorage和localStorage的区别
保存方式
cookie存放在客户的浏览器上。
session都在客户端中保存,不参与服务器通讯。
生命周期
cookie可设置失效时间
localStorage除非手动清除否则永久保存
sessionStorage关闭当前页面或浏览器关闭后失效
存储的大小
cookie 4kb
session 5M
共同点
不能存储其他数据类型,只能存储字符串数据类型
如果一定要存储其他数据类型,转成 json 格式存储
使用方法
1 | var storage = null; |
BFC
BFC
(Block Formatting Context),即块级格式化上下文,它是页面中一个独立的容器,容器中的元素不会影响到外面的元素。
触发条件
触发BFC
的条件包含不限于:
- 根元素,即HTML元素
- 浮动元素:float值为left、right
- overflow值不为 visible,为 auto、scroll、hidden
- display的值为inline-block、inltable-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid
- position的值为absolute或fixed
CSS部分
CSS选择器的优先级排序
选择器类型
选择器 | 表现形式 |
---|---|
id | #id,例如:id=“name”,id=“password” |
class | .class,例如:class=“name”,class=“password” |
标签 | 例如:body、div、p、ul、li |
属性 | [type=‘text’] |
伪类 | :hover,例如:链接样式,a元素的伪类,有4种不同的状态:link、visited、active、hover。 |
相邻选择器、子代选择器 | +、>,例如:div > p,带大于号 ’>’ |
通配符选择器 | * |
!important > 行内样式 > id选择器 > 类选择器 || 伪类选择器 || 属性选择器 > 标签选择器 || 伪元素选择器 > 通配符选择器 || 子选择器 || 相邻选择器 > 继承样式
1 | * 第零等:!important,大过了其它任何设置。 |
垂直居中DIV
请看这里css之div盒子居中常用方法
清除浮动
父级盒子添加overflow方法
优点:简单、代码少、浏览器支持好
缺点:内容被隐藏掉,无法显示需要溢出的元素,不能和position配合使用
使用after伪元素清除浮动:
用法:给浮动元素父级增加
.clearfix::after(content: ‘’; display: table; clear: both;)
优点: 符合闭合浮动思想,结构语义化正确,不容易出现怪问题
缺点: 由于IE6-7不支持
:after
,使用zoom:1
父级盒子定义height:
优点: 简单、代码少。
缺点:只适合高度固定的布局,要给出精确的高度
额外标签法:
用法: 在浮动元素后使用一个空元素,并在 CSS 中赋予
.clear{clear:both;}
属性即可清理浮动。优点: 通俗易懂,书写方便。
缺点: 添加许多无意义的标签,结构化比较差。
盒子模型
盒模型由内容(content)、内边距(padding)、边框(border)、外边距(margin)组成。
盒模型分为IE盒模型和W3C标准盒模型。
W3C标准盒模型又叫content-box,元素宽度/高度由border+padding+content组成。
(属性width,height只包含内容content,不包含border和padding)
IE盒模型又叫border-box,元素宽度/高度由content组成。
(属性width,height包含border和padding,指的是content+padding+border。)
padding和margin的区别
- margin是盒子的外边距,即盒子与盒子之间的距离,而padding是内边距,是盒子的边与盒子内部元素的距离。
- margin是用来隔开元素与元素的间距;padding是用来隔开元素与内容的间隔
- margin用于布局,可以分开元素,使元素与元素互不相干;padding用于设置元素与内容之间的间隔,让内容(文字)与(包裹)元素之间有一段“呼吸距离”。
有哪些方式可以隐藏页面元素?区别?
通过css
实现隐藏元素方法有如下:
- display:none
- visibility:hidden
- opacity:0
- 设置height、width模型属性为0
- position:absolute
- clip-path
display: none | visibility: hidden | opacity: 0 | |
---|---|---|---|
页面中 | 不存在 | 存在 | 存在 |
重排 | 会 | 不会 | 不会 |
重绘 | 会 | 会 | 不一定 |
自身绑定事件 | 不触发 | 不触发 | 可触发 |
transition | 不支持 | 支持 | 支持 |
子元素可复原 | 不能 | 能 | 不能 |
被遮挡的元素可触发事件 | 能 | 能 | 不能 |
重绘和重排是什么?如何避免?
- 重排:当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。
- 重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,所以重绘跳过了创建布局树和分层的阶段。
- 重排需要重新计算布局树,重绘不需要,重排必定发生重绘,但是涉及到重绘不一定要重排。
- 触发重排的方法: 页面初始渲染、添加/删除可见的DOM元素、改变元素位置、改变元素尺寸、改变元素内容、改变元素字体大小、改变浏览器窗口尺寸、设置 style 属性的值等。
- 避免重排的方式:样式集中改变、使用 absolute 或 fixed 脱离文档流。
CSS中有哪些长度单位?
- 绝对长度单位:px
- 百分比: %
- 相对父元素字体大小单位: em
- 相对于根元素字体大小的单位: rem
- 相对于视口*宽度的百分比(100vw即视窗宽度的100%): vw
- 相对于视口*高度的百分比(100vh即视窗高度的100%): vh
JavaScript和ES6部分
ES6新特性?
- 新增块级作用域,let定义变量和const定义常量
- 变量的解构赋值
- 箭头函数(=>)
- 扩展运算符(…)
- 模块(import/export)
- 类(class/extends)
- Promise
- Proxy
- Symbol
- Set数据结构,类似于数组,但是成员的值都是唯一的,没有重复的值
- includes()用于判断数组是否包含给定的值 返回一个布尔值
- find()用于找出第一个符合条件的数组成员
- findindex()返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1
Set和Map的区别
- Map是键值对,Set是值的集合,键和值可以是任何的值
- Map可以通过get方法获取值,而Set不能因为它只有值,Set只能用has来判断,返回一个布尔值
- Set的值是唯一的可以做数组去重,Map由于没有格式限制,可以做数据存储
闭包的理解和使用场景
- 理解:闭包就是函数中包含另一个函数,可以让你在函数外部读取到内部的变量(就是在函数内部再定义一个函数),让这些变量的值始终保持在内存中,可以达到延长变量生命周期的效果,过多使用会导致内存泄漏的问题。
- 优点:可以避免全局变量造成污染。
- 缺点:闭包会常驻内存,增加内存使用量,使用不当会造成内存泄漏。
- 特征:(1)函数嵌套函数。(2)在函数内部可以引用外部的参数和变量。(3)参数和变量不会以垃圾回收机制回收。
- 使用场景:(在创建私有变量和想延长变量的生命周期时会用到闭包)
JS获取HTML DOM元素的方法
- 通过ID获取(getElementById)
- 通过name属性(getElementsByName)
- 通过标签名(getElementsByTagName)
- 通过类名(getElementsByClassName)
- 获取html的方法(document.documentElement)
- 获取body的方法(document.body)
- 通过选择器获取一个元素(querySelector)
- 通过选择器获取一组元素(querySelectorAll)
事件捕获和事件冒泡
- 事件捕获:事件从文档根节点流向目标节点,途中会经过目标节点的各个父级节点,并在这些节点上触发捕获事件,直至到达事件的目标节点。
- 事件冒泡:与事件捕获相反,事件会从目标节点流向文档根节点,途中会经过目标节点的各个父级节点,并在这些节点上触发捕获事件,直至到达文档的根节点。整个过程就像水中的气泡一样,从水底向上运动。
- event.stopPropagation() 可以阻止事件流的进一步传播。
注意:stopPropagation()会阻止事件捕获和事件冒泡,但是无法阻止标签的默认行为,例如点击链接任然可以打开对应网页。
Var、 let 、const 区别?
变量提升:
var
声明的变量存在变量提升,即变量可以在声明之前调用,值为undefinedlet
和const
不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错暂时性死区:
var
不存在暂时性死区let
和const
存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量块级作用域:
var
不存在块级作用域let
和const
存在块级作用域重复声明:
var
允许重复声明变量let
和const
在同一作用域不允许重复声明变量修改声明的变量:
var
和let
可以const
声明一个只读的变量,一旦声明,就不能改变了使用:
能用
const
的情况尽量使用const
,其他情况下大多数使用let
,避免使用var
== 和 ===区别
- 相等操作符(==)会做类型转换,再进行值的比较,全等运算符(===)不会做类型转换
1 | let result1 = ("123" === 123); // false,不相等,因为数据类型不同 |
null
和undefined
比较,相等操作符(==)为 true,全等为 false
1 | let result1 = (null == undefined ); // true |
- 相同点:都是判定两个值是否相等
不同点:== 只比较值不比较类型,而 ===会判断类型
什么是防抖和节流?
防抖:n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
应用场景:提交按钮、用户注册时候的手机号验证、邮箱验证
节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
应用场景:射击游戏中的mousedown、keydown事件,文字输入、自动完成的keyup事件
电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖
电梯第一个人进来后,15秒后准时运送一次,这是节流
原型,原型链 ?
原型:每个函数对象都有一个 prototype 属性,这个属性就是函数的原型对象。
原型链:当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的
__proto__
隐式原型上查找,即它的构造函数的prototype
,如果还没有找到就会再在构造函数的prototype
的__proto__
中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。注:原型链的形成是真正是靠
__proto__
而非prototype
深拷贝浅拷贝的区别?
浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
总而言之,浅拷贝改动拷贝的数组原数组也会变(慎用!项目中很多地方共用的数组都会变)。深拷贝修改新数组不会改到原数组。
浅拷贝:
- Object.assign()
- 函数库lodash的 _.clone 方法
- es6的展开运算符 …
- Array.prototype.concat()
- Array.prototype.slice()
深拷贝:
- JSON.parse(JSON.stringify())
- 函数库lodash的 _.cloneDeep 方法
- jQuery.extend()方法
- 手写递归方法
经典案例:
- 数组和对象,都是浅拷贝
- 解构(…)数组是深拷贝一层,对于一维的数组是深拷贝,多维的只能算是浅拷贝
1 | <script> |
JavaScript中的数据类型?
- 基本类型
- Number:数值,包括整型和浮点型。
- String:字符型。
- Undefined:未定义,声明变量时未赋值。
- Null:定义为空或者不存在。
- Boolean:布尔值,true or false。
- Symbol:独一无二的值。
- 引用数据类型
- Object:对象。
- Array:数组。
- Function:函数。
Promise
- 含义:异步编程的一种解决方案,用来解决回调地狱。
- 三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
- resolved函数作用:将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved)。
- reject函数的作用:将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected)。
- Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
GET和POST的区别
- 后退/刷新:GET无害,POST数据会被重新提交。
- 数据:GET一般是用来获取数据,POST提交数据。
- 数据类型:GET只允许ASCII字符,POST无限制。
- 数据大小:GET大小有限制(一般来说1024字节),POST理论上来说没有大小限制。
- 安全性:GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- 可见性:GET参数通过URL传递对所有人可见,POST数据不可见。
- 历史保留:GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- 书签:GET产生的URL地址可以被收藏为书签,而POST不可以。
数组常用方法
增
- push() 接收任意数量的参数,并将它们添加到数组末尾
- unshift() 开头添加
- concat() 方法用于连接两个或多个数组。
实例:
1 | var hege = ["Cecilie", "Lone"]; |
children
输出结果:
1 | Cecilie,Lone,Emil,Tobias,Linus,Robin |
删
- pop() 删除数组的最后一项
- shift() 删除数组的第一项
- splice() 传入两个参数,分别是开始位置,删除元素的数量
- slice() 可以用来从数组中提取元素,该方法不会改变元素数组,而是将截取到的元素封装到一个新数组返回
改
- splice() 方法用于添加或删除数组中的元素。
实例:
1 | var fruits = ["Banana", "Orange", "Apple", "Mango"]; |
fruits
的输出结果:
1 | Banana,Orange,Lemon,Kiwi,Apple,Mango |
参数 | 描述 |
---|---|
index | 必需。规定从何处添加/删除元素。 该参数是开始插入和(或)删除的数组元素的下标,必须是数字。 |
howmany | 可选。规定应该删除多少元素。必须是数字,但可以是 “0”。 如果未规定此参数,则删除从 index 开始到原数组结尾的所有元素。 |
item1, …, itemX | 可选。要添加到数组的新元素 |
查
- indexOf() 返回要查找的元素在数组中的位置,如果没找到则返回 -1
- includes() 返回要查找的元素在数组中的位置,找到返回
true
,否则false
- find() 返回第一个匹配的元素
数组去重
- 利用ES6的**…new Set()**去重,最方便最简单
1 | <script> |
- 利用双重循环和splice()来去重
1 | <script> |
- 利用indexOf去重,indexOf() 返回要查找的元素在数组中的位置,如果没找到则返回 -1。
1 | <script> |
注意:利用**includes()也和indexOf()**的方法差不多,includes() 返回要查找的元素在数>组中的位置,找到返回
true
,否则false
JS中new操作符有什么用?
- 创建临时对象,并将this指向临时对象
- 将构造函数的原型属性和方法挂载到新对象的__proto__(原型指针)上
- return 临时对象
排序方式
- 冒泡排序:比较所有相邻元素,如果第一个比第二个大,则交换它们。
- 选择排序:找到数组中的最小值,选中它并将其放置在第一位。
- 插入排序:从第二个数开始往前比,比它大就往后排。
- 归并排序:把数组劈成两半,再递归地对数组进行“分”操作,直到分成一个个单独的数。
- 快速排序:从数组中任意选择一个基准,所有比基准小的元素放到基准前面,比基准大的元素放到基准的后面。
Vue部分
数据双向绑定原理
- 通过数据劫持结合发布-订阅模式,通过Object.defineProperty()为各个属性定义get、set方法,在数据发生改变时,给订阅者发布消息,触发相应的事件回调
Vue生命周期
- 从创建、初始化数据、编译模板、挂载DOM、渲染-更新-渲染、卸载等一系列过程,称为为Vue 实例的生命周期。
Vue导航守卫的钩子函数有哪些
全局守卫:
- router.beforeEach:全局前置守卫,进入路由之前
- router.beforeResolve:全局解析守卫,在beforeRouteEnter调用之后调用
- router.afterEach:全局后置钩子,进入路由之后
路由守卫:
- beforeRouteEnter():进入路由前
- beforeRouteUpdate():路由复用同一个组件时
- beforeRouteLeave():离开当前路由时
组件之间如何传值
- Vue父子组件之间传值
- 子组件通过props来接受数据和通过
$emit
来触发父组件的自定义事件;
- 兄弟组件之间的传值
- 建一个公共组件bus.js.。传递方通过事件触发
bus.$emit
。接收方通过在mounted(){}生命周期里触发bus.$on
。
- 可以通过VUEX 来跨组件传参。
MVVM是什么
Model-View-ViewModel的缩写,把MVC中的Controller层变成ViewModel层,Model代表数据模型,View代表UI组件,MVVM实现了View层和Model层的自动同步,也即是我们不用手动操纵哦Dom元素
MVVM与MVC的区别有:
MVVM与MVC的最大区别就是:它实现了View和Model的自动同步,也就是当Model的数据改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变数据后该数据对应View层显示会自动改变。MVVM并不是用VM完全取代了C,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现
路由之间如何传参
- 通过router-link路由导航跳转传递
1 | <router-link to=`/a/${id}`>routerlink传参</router-link> |
- 跳转时使用push方法拼接携带参数。
1 | this.$router.push({ |
- 通过路由属性中的name来确定匹配的路由,通过params来传递参数。
1 | this.$router.push({ |
- 使用path来匹配路由,然后通过query来传递参数。
1 | this.$router.push({ |
Route和router的区别
- router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,包含了所有的路由包含了许多关键的对象和属性。例如history对象。
- $router.push({path:’/path’}); 本质是向history栈中添加一个路由,在我们看来是 切换路由,但本质是在添加一个history记录
- $router.replace({path:’/path’}); 替换路由,没有历史记录
- route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等。
- $route.path
字符串,等于当前路由对象的路径,会被解析为绝对路径,如 “/index/” 。 - $route.params
对象,包含路由中的动态片段和全匹配片段的键值对 - $route.query
对象,包含路由中查询参数的键值对。例如,对于 /index?id=1 ,会得到 $route.query.id == 1。
Vue 路由跳转方式
- router-link 标签跳转
- this.$router.push()
- this.$router.replace()
- **this.$router.go(n)**:(0:当前页,-1上一页,+1下一页,n代表整数)
Vue中key是用来做什么的?为什么不推荐使用index作为key?
- key的作用主要就是为了高效的更新虚拟DOM,使用key值,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。它也可以用于强制替换元素/组件而不是重复的使用它。
- 当以数组的下标index作为index值时,其中一个元素(如增删改查)发生了变化就有可能导致所有元素的key值发生变化。
说出至少vue 3个常用事件修饰符?
.stop 阻止点击事件冒泡
.prevent 阻止默认事件
.once 只执行一次
.self 只在元素本身触发
vuex有哪几种属性
- state:vuex的基本数据,用来存储变量。
- mutation:提交更改数据,同步更新状态。
- action:提交mutations,异步操作。
- getter:是store的计算属性。
- modules:模块化vuex,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。