一、CSS面试题
1. 清除浮动的方式有哪些?
- 为什么要清除浮动?因为浮动的盒子脱离标准流,如果父盒子没有设置高度的话,下面的盒子就会撑上来。
- 额外标签法(在最后一个浮动标签后,新加一个标签,给其设置clear: both; ) (不推荐)
- 父级添加overflow属性 (父元素添加overflow:hidden) (不推荐)
- 使用after伪元素清除浮动 (推荐使用)
.clear:after{
content:''; display:block;
overflow:hidden;
visibility:hidden;
clear:both;
}
- 使用before 和 after 伪元素清除浮动
```javascript
.clearfix:after,.clearfix:before{
content: "";
display: table;
}
.clearfix:after{
clear: both;
}
.clearfix{
*zoom: 1;
}
2. position 几 个 属 性 的 作 用 ?
- position的常见四个属性值: relative,absolute,fixed,static。一般都要配合"left"、“top”、“right"以及"bottom” 属性使用。
(1)static:默认位置,(static 元素会忽略任何 top、 bottom、left 或 right 声明)。一般不常用。
(2)relative:位置被设置为 relative 的元素,偏移的 top,right,bottom,left 的值都以它原来的位置为基准偏移。注意 relative 移动后的元素在原来的位置仍占据空间。
(3)absolute:位置设置为 absolute 的元素,可定位于相对于包含它的元素的指定坐标。意思就是如果它的父容器设置了 position 属性,并且 position 的属性值为 absolute 或者 relative,那么就会依据父容器进行偏移。如果其父容器没有设置 position 属性,那么偏移是以 body 为依据。注意设置 absolute 属性的元素在标准流中 不 占 位 置 。
(4)fixed:位置被设置为 fixed 的元素,可定位于相对于浏览器窗口的指定坐标。不论窗口滚动与否,元 素都会留在那个位置。它始终是以body 为依据的。注意设置 fixed 属性的元素在标准流中不占位置。
3. 在一个页面中给多个元素设置相同的 id, 会导致什么问题?
- 会导致通过 js 获取 dom 元素的时候, 只能获取到第一个元素, 后面的元素都无法正常获取。
4. Less 是什么?
- Less 是一种 css 预处理语言, 在 less 中可以定义一些变量和表达式以及使用嵌套语法; less 中使用@定义变量(@baseColor:pink);后期可以通过一些编译工具(less)将 less 编译成浏览器能直接识别的css 样式。所以 less 只是在开发阶段使用的一种中间语言, 使用less 的目的是提高开发效率以及提高代码的可维护性。
5. Scss 是什么?(sass)
- scss 是一种 css 预处理语言,在 less 中可以定义一些变量和表达式以及使用嵌套语法;scss 中使用
定义变量
(
定义变量(
定义变量(baseColor:pink); 后期可以通过一些编译工具(node-sass)将 less 编译成浏览器能直接识别的 css 样式。所以 scss 只是在开发阶段使用的一种中间语言,使用 scss 的目的是提高开发效率以及提高代码的可维护性。
6. Stylus 是什么?(.styl)
- stylus 是一种 css 预处理语言, 在 stylus 中可以定义一些变量和表达式以及使用嵌套语法(stylus 中是使用缩进的语法表示嵌套关系);后期可以通过一些编译工具(stylus)将 stylus 编译成浏览器能直接识别的css 样式. 所以stylus 只是在开发阶段使用的一种中间语言,使用 stylus 的目的是提高开发效率以及提高代码的可维护性。
7. 写一个左中右布局占满屏幕, 其中左右两块固定宽度 200,中间自适应,要求先加载中间块, 请写出结构和样式?
*{
padding: 0;
margin: 0;
}
html,body{ heig
ht: 100%;
}
.center{ heigh
t: 100%;
background: #1FA363;
margin:0 200px;
}
.left{
position: absolute;
width: 200px;
height: 100%;
left: 0;
top: 0;
background: #DC4C3F;
}
.right{
position: absolute;
width: 200px;
height: 100%;
right: 0;
top: 0;
background: #FFCE44;
}
<div class="center">center</div>
<div class="left">left</div>
<div class="right">right</div>
8. 页面编码和被请求的资源编码如果不一致如何处理?
- html 的编码是 gbk 或 gb2312 的。 而引入的 js 编码为 utf-8 的 ,那就需要在引入的时候,同理,如果你的页面是 utf-8 的,引入的 js 是 gbk 的,那么就需要加上 charset=“gbk”。
<script src="http://www.xxx.com/test.js" charset="utf-8"></script>
9. 遇到过哪些移动端兼容性问题?
- 不同浏览器的最小字体不同,有的是10px,有的是12px。
解决办法:设置字体时,不要小于12px,如果一定要小于12px,使用transform:sacle( ) 进行缩放。
- 移动端文字实现两端对齐,使用text-align-last在ios会有兼容性问题。
使用text-align-last:justify; 在安卓上面表现没有问题,但是在ios上面不会对齐。
解决办法:在当前的元素后面添加一个after伪类,并给当前的元素设置行高为0,如下:
span {
text-align: justify;
text-align-last: justify;
line-height: 0px;
&::after {
content: "";
width: 100%;
display: inline-block;
}
}
- scrollTo(0,0)和scrollTop=0
苹果低版本的手机上不支持获取使用dom.scrollTo(0,0),使用该方法会报错。 换言之,使用dom.scrollTop=0,就可以正常使用。
- 用position:absolute/fixed;把一个按钮固定在页面的底部,在android系统中,当调用输入法时,该按钮会被顶起。
解决办法:使用媒体查询@media screen and (max-width:400px){}当页面高度小于某一个值时,给元素一个top值,不同浏览器默认margin,padding不同。解决办法:*{margin:0;padding:0;}
- click事件延迟的问题。
移动端的点击事件都会有300ms延迟,是因为浏览器在等待你是否执行双击,但此延迟导致用户体验不好。 解决办法: 用script标签引入fastclick库去除延迟, 禁止缩放 user-scable=“no” 。
二、js面试题
1. 什么是原型对象?
- 每一个构造函数都有一个 prototype 的属性, 这个属性的值是一个对象, 这个对象就叫做构造函数的原型对象;一般建议将构造函数的成员属性绑定在原型对象 prototype 上,因为原型对象 prototype 身上的属性默认可以通过实例对象访问到;这样做可以保证在每次通过 new 关键字创建实例对象的时候, 这些方法不会被重复在内存中创建。
2. 什么是原型链?
- 每个构造函数都有一个 prototype 属性, 即原型对象, 通过实例对象的 proto 属性也可访问原型对象;而原型对象本质也是一个对象, 是对象就有自己的原型对象, 最终形成的链状的结构称为原型链。
3. 什么是构造函数?
- 构造函数本质也是一个函数, 只不过这个函数在定义的时候首字母一般需要大写; 构造函数调用的时候,必须通过一个 new 关键字来调用; 我们一般不直接使用构造函数, 而是使用构造函数创建出来的实例对象,构造函数是 js 面向对象的一个重要组成部分。
3. 常见的继承有哪些?
- 原型链继承
- 借用构造函数继承
- 组合继承
- 原型式继承
- class类实现继承
通过extends 和super实现继承
- 寄生式继承
4. this的指向有哪些?
- 普通函数中的this指向window
- 定时器中的this指向window
- 箭头函数中没有this,它的this指向取决于外部环境
- 事件中的this指向事件的调用者
- 构造函数中的this指向和原型对象中的this,都是指向构造函数new出来的实例对象
- 自执行函数中的this指向window
5. 什么是递归?
- 函数内部自己调用自己,这个函数就是递归。
- 优点:结构清晰,可读性强。
- 缺点:效率低,调用栈可能会溢出,每一次函数调用会在内存栈中分配空间,而每个进程的栈的容量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出。
6. 你平时都用了哪些方法进行性能优化?
资源加载方面:
- 减少http的请求次数 具体方案, 代码合并(合并 css,js), 使用精灵图; 减少 http 请求数据量, 代码压缩(css,js,html), 合理设置缓存。
- 打包压缩的上线代码
- 使用懒加载
- 使用精灵图
- 动态渲染组件
- CDN加速
代码层面:
- 避免滥用全局变量, 减少作用域查找(能用局部变量就不要声明全局变量), 不要滥用闭包;
- 减少 DOM 操作, 操作 DOM 的时候对已经查找到的 DOM 对象进行缓存, 避免重复查找;
- 使用图片懒加载, 避免单次加载图片数量过多导致页面卡顿; 将script 标签写在页面底部, 因为 js 的加载会阻塞页面的渲染;
- 不要在本地书写大量 cookie, 因为 cookie 会伴随每一次 http 请求;
7. js的执行机制是怎么样的?
- js是一个单线程,异步、非阻塞的eventLoop事件循环的执行机制。
所有的任务都可以分为两种,一种是同步任务 (synchronous),另一种是异步任务 (asynchronous)。
- 同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。
- 异步任务指的是,不进入主线程、而进入"任务队列”的任务,只有“任务队列"通知主线程某个异步任务可以执行了,该任务才会进入主线程执行。
8. 知道lodash吗? 它有哪些常见的API?
- Lodash是一个一致性、模块化、高性能的JavaScript 实用工具库
- .cloneDeep 深度拷贝
- .reject 根据条件去除某个元素
- .drop(array,[n=1])作用: 将 array 中的前 n 个元素去掉,然后返回剩余的部分
9. set和map是什么?
- set 是es6 提供的一种新的数据结构,它类似于数组,但是成员的值都是唯一的。
- map 是es6 提供的一种新的数据结构,它类似于对象,也是键值对的集合,但是键的范围不仅限于字符串,各种类型的值都可以当做键。也就是说,Object 结构提供了“字符串一值”的对应,Map 结构提供了”值一值”的对应,是一种更完善的 Hash 结构实现。如果你需要"键值对”的数据结构,Map 比 object更合适。
10. 简述以下es6中的类?
- es6中的class可以把它看成是es5中构造函数的语法糖,它简化了构造函数的写法,类的共有属性放到constructor 里面。
- 通过class 关键字创建类,类名我们还是习惯性定义首字母大写。
- 类里面有个constructor 函数,可以接受传递过来的参数,同时返回实例对象。
- constructor 函数 只要 new 生成实例时,就会自动调用这个函数, 如果我们不写这个函数类也会自动生成这个函数
- 多个函数方法之间不需要添加逗号分隔。
- 生成实例 new不能省略。
- 语法规范,创建类 类名后面不要加小括号,生成实例 类名后面加小括号,构造函数不需要加function。
(1)继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的。
(2)继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近
原则)。
(3)如果子类想要继承父类的方法,同时在自己内部扩展自己的方法,利用super 调用 父类的构造函数,super 必须在了类this之前调用。 - 时刻注意this的指向问题,类里面的共有的属性和方法一定要加this使用。
(1)constructor中的this指向的是new出来的实例对象。
(2)自定义的方法,一般也指向的new出来的实例对象。
(3)绑定事件之后this指向的就是触发事件的事件源。
(4)在ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象。
11. call、apply、bind三者的异同?
- 共同点 : 都可以改变this指向;
- 不同点: call 和apply 会调用一次函数,并且改变函数内部this指向; 而 bind 不会调用函数,可以改变函数内部的this指向。call 和apply传递的参数不一样,call 从第二个参数开始需要一个参数列表,apply 第二个参数需要是一个数组。
- 应用场景
- call 经常做继承。
function fn(a,b,c){
console.log(this,a+b+c); // this指向window
}
fn();
fn.call(document,1,2,3);//call改变之后this指向document
//输出 #document 6 1,2,3是实参 结果相加为6
- apply经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值。
function fn(a,b,c){
console.log(this,a+b+c);
}
fn();
fn.apply(document,[1,2,3]);
- bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向。
function fn(a,b,c){
console.log(this,a+b+c); //window
}
let ff = fn.bind('小明',1,2,3); //手动调用一下
12. 列举和数组操作相关的方法
- push:将元素添加到数组的末尾, 返回值是数组长度
- pop:将数组最后一个元素弹出, 返回值是被弹出的元素
- unshift:在数组的开头插入一个元素,返回值是数组的长度
- shift:将数组第一个元素弹出,返回值是被弹出的元素
- splice(index,len):删除数组中指定元素
- concat:连接数组
- reverse: 翻转数组
13. 列举和字符串操相关的方法
- substr(start,len)/substring(start,end): 截取字符串
- slice:从数组会字符串中截取一段
- indexOf/lastIndexOf:查找某一个字符是否存在于另外一个字符串中, 存在则返回索引, 不存在则返回-1;indexOf 是从前向后顺序查找;
- lastIndexOf:是从后向前查找
- replace:替换字符串特定的字符
- toUpperCase:将字符串转成大写
- toLowerCase:将字符串转成小写
- charAt:获取字符串中指定索引的字符
14. 例举 3 种强制类型转换和 2 种隐式类型转换?
- 强制转换:转化成字符串 toString() 、String() 、转换成数字 Number()、parseInt()、 parseFloat()。
- 隐式转换:转换成布尔类型 Boolean() 隐式拼接字符串,例子 var str = “” + - / % ===
15. 分别阐述 split()、slice()、splice()、join()?
- split 可以使用一个字符串切割另外一个字符串, 返回值是数组
- slice 可以从数组中截取一部分(字符串对象也有 slice 方法)
- splice(index,len)可以删除指定的数组元素;
- join 可以将数组元素使用特定的连接符拼接成字符串
15. 什么是预解析?
- JS 代码在执行之前,解析引擎会对代码进行一个预先的检查, 主要会对变量和函数的声明进行提升, 将变量和函数的声明提到代码的最前面,变量只提升声明,不提升赋值。
16. 使用js封装一个冒泡排序?
function sortBubble(arr){
for(var i=0;i<arr.length;i++){
for(var j=0;j<arr.lengthi;j++){ if(arr[j]>arr[j+1]){
var temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
return arr;
17. 使用 js 求 10000 以内的所有质数的和?
function getZs(num) {
var sum=0;
for (var i = 2; i <= num; i++) {//4
//假设所有的数都是质数
var flag = true;
//通过嵌套循环找到 i 除了 1 和本身以外所有可能出现的因子
for (var j = 2; j < i; j++) {
//判断 i 是否为质数
if (i % j == 0) {//能进到当前的分支 说明不是质数
flag = false;
}
}
if (flag == true) {
console.log(i);
sum+=i;
}
}
return sum;
}
18. 二维数组根据 num 的值进行升序排序?
var list = [
{
id: 32, num: 5
},
{
id: 28, num: 12
},
{
id: 23, num: 9
}]
// 实现过程
list.sort(function(a,b){ r
eturn a.num-b.num;
})
19. Js 中 eval 的功能是什么? 缺点是什么?
- eval 函数的作用:可以将一个字符串当做 js 代码执行。缺点: 执行效率比较低,不安全。
20. 列举 DOM 元素增删改查的 API
- 创建 DOM: document.createElement();
- 查 找 DOM: document.getElementById(); document.getElementsByClassName(); document.getElementsByName(); document.querySelectorAll(); document.querySelector();
- 追加 DOM: parentDom.appendChild();
- 移除 DOM: parentDom.removeChild()。
21. BOM 中有哪些常用的对象?
location:
location.href; 页面 url 地址
location.hash; url 中#后的部分
location.search; url 中?后的部分(查询字符串)
location.reload(); 刷新页面;
navigator:
navigator.userAgent: 浏览器的 userAgent 信息
history:
history.go(1);前进 1 步
history.go(-1);后退 1 步;
history.forward();前进
history.back(); 后退
screen:
screen.availWidth: 屏幕有效宽度
screen.availHeight: 屏幕有效高度
22. 列举几个常见的浏览器兼容问题?
主流浏览器发送 ajax 使用 XMLHttpRequest 创建异步对象,
IE 浏览器时候用 XActive 创建异步对象;
主流浏览器注册事件
addEventListener("eventType","handler","true|false");
removeEventListner("eventType","handler","true|false");
IE 浏览器:
注册事件:attachEvent( "eventType","handler")
移除事件:detachEvent("eventType","handler" )
阻止事件冒泡:
主流浏览器:event.stopPropagation()
IE 浏览器:event.cancleBubble=true;
获取事件源:
主流浏览器: event.target
IE 浏览器:event.srcElement
23. 请尽可能详尽的解释 ajax 的工作原理
- 第一步:创建一部对象 var xhr=new XMLHttpRequest()
- 第二步:设置请求行 xhr.open(‘请求方式’,请求地址);
- 第三步:发送请求 Get 方式 xhr.send(null),如果是 post 请求还要设置请求头。
- 第四步:监听服务端的响应。
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded ');
xhr.send("name=zs&age=18");
//第四步:监听服务端的响应
xhr.onreadystatechange=function(){
if(xhr.status==200&&xhr.readyState==4){
// 获取 json
var json=xhr.responseText&&JSON.parse(xhr.responseText)
// 获取 xml
var xml=xhr.responseXML;
console.log(json,xml)
}
}
24. 什么是同步和异步, 那种执行方式更好?
- 同步是指一个程序执行完了接着去执行另外一个程序, 异步是指多个程序同时执行. 所以异步效率更高, 因为异步不会出现阻塞现象, 前一个程序的执行不会影响后一个程序的执行。
25. 什么是 RESTful API?
- RESTful 的核心思想就是使用 HTTP 请求方式配合资源对象的方式来完成对服务端某个资源的操作(HTTP 动词+资源对象)。比如,GET /articles 这个命令,GET 是 HTTP 动词,/articles 是资源对象。
补充说明:
动词通常就是五种 HTTP 方法,对应 CRUD 操作:
GET:读取(Read)
POST:新建(Create)
PUT:更新(Update)
PATCH:更新(Update),通常是部分更新
DELETE:删除(Delete)
26. 谈谈 async/await 的使用方式和场景
- async 是用来修饰函数的声明, 使用async 修饰的函数会变成一个异步函数. await 用来修饰函数的调用, 被 await 修饰的函数必须返回一个promise 异步对象, 使用 await 修饰后, 就会将 promise 异步对象转换成一个同步操作。
27. 箭头函数有什么作用及实际应用场景?
- 箭头函数可以使函数内部的 this 指向和函数外部保持一致; 箭头函数之所以可以让函数内部的 this 指向和外部保持一致是因为箭头函数内部没有 this 指向. 可以在 ajax 的回调函数中使用箭头函数让回调函数中的 this 指向事件源;可以在定时器的第二个参数中使用箭头函数,避免函数内部的 this 指向全局 window。
28. 谈谈对 Promise 的理解
- Promise 本身并没有提供任何的代码逻辑, 它可以帮助我们改造或优化传统的使用回调函数实现的异步操作, 让我们以一种更优雅的方式来实现异步操作。 最显著的一个特点就是通过 Promise 可以解决传统的回调地狱。代码层面 Promise 提供了一个构造函数,在使用的时候必须通过 new 创建一个实例对象, 在创建实对象的时候需要传递一个匿名函数,这个匿名函数需要两个参数(resolve,reject), resolve 成功处理函数,reject 失败处理函数。什么时候触发成功处理函数和失败处理函数,由具体的业务逻辑来决定。resolve 和 reject 需要通过Promise 实例对象提供的 then 方法来传递.Promise 提供了两个静态方法 al、race,all 可以一次执行多个 Promise 实例, 返回值是数组; race 也可以一次执行多个 Promise 实例, 哪个实例最先执行完, 就返回哪个的执行结果。
29. break和continue和return的区别?
- break
(1) break用于跳出一个循环体或者完全结束一个循环,不仅可以结束其所在的循环,还可以结束其外层循环。
(2) 只能在循环体内和switch语句内使用break。
(3) 不管是哪种循环只要一旦在循环体中遇到bre eak系统将完全结束循环,开始执行循环后的代码。
(4)在switch语句中,满足某种条件就会跳出本层循环体。 - continue
(1)continue:只是中止本次循环,然后开始下一次循环。
(2)continue并没有使整个循环终止。
(3)continue只能在循环语句中使用。for循环、 while循环、do…while循环中使用。 - return
(1)return是结束一个方法。如果在循环体内执行一个return语句,return语句将会结束该方法,循环也会随之结束。
30. const 声明的变量不可以修改怎么理解?
- const 声明的限制只适用于它指向的变量的引用。换句话说,如果 const 变量引用的是一个对象, 那么修改这个对象内部的属性并不违反 const 的限制。
- 《ES6教程》这样写:const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
三、网络
1. HTTP状态码分别代表什么意思?
- 1xx 表示HTTP请求已经接受,继续处理请求 2xx 表示HTTP请求已经处理完成(200) 3xx 表示把请求访
问的URL重定向到其他目录(304资源没有发生变化,会重定向到本地资源) 4xx 表示客户端出现错误
(403禁止访问、404资源不存在) 5xx 表示服务端出现错误。
2. 什么是SEO?
- SEO(Search Engine Optimizing)搜索引擎优化, 就是让搜索引擎去抓取我们的网页. 为了让搜索引擎抓取我们的网页, 我们可以在书写代码的时候做一些工作, 比如合理设置网页 title(标题), keywords(关键字),description(描述); 因为搜索引擎在抓取到网页以后首先回去分析这几个关键信息。
3. 什么是渐进增强和优雅降级?
- 渐进增强(progressive enhancement):针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。(从被所有浏览器支持的基本功能开始,逐步地添加那些只有新式浏览器才支持的功能,向页面添加无害于基础浏览器的额外样式和功能。当浏览器支持时,它们会自动地呈现出来并发挥作用。)
- 优雅降级(graceful degradation):一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。(Web 站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会检查以确认它们是否能正常工作。由于 IE 独特的盒模型布局问题,针对不同版本的IE 的 hack 实践过优雅降级了,为那些无法支持功能的浏览器增加候选方案,使之在旧式浏览器上以某种形式降级体验却不至于完全失效。)
区别:优雅降级是从复杂的现状开始,并试图减少用户体验的供给,而渐进增强则是从一个非常基础的、能够起作用的版本开始,并不断扩充,以适应未来环境的需要。
4.什么是 CDN 加速?
- CDN(Content Delivery Network)全称内容分发网络, 是运营商所提供的一项增值服务, 花钱就可以拥有这项加速服务。CDN 主要是对网站的静态资源进行加速, CDN 在全国会有很多节点服务器(每个城市都有), 当你购买了一个CDN 服务以后, CDN 服务器会对你的网站的静态资源文件进行缓存处理, 当第二次有人访问的时候, 那么服务器就会从就近的 CDN 节点服务器上获取网站所需的静态资源, 由于 CDN 服务器的性能比较高, 并且距离客户端的物理距离比较近, 所以就可以实现加速. 启用 CDN 服务只需要在运营提供商提供的后台进行配置(配置要对那个域名启用 CDN 服务), 不需要对代码做任何修改。
5. 为什么利用多个域名来存储网站静态资源会更有效?
- 因为浏览器对请求静态资源文件有一个并发数量限制, 每次只能请求同一个域名下的若干个资源文件(根据浏览器的不同会有差异), 如果把资源文件存放在多个不同的域名下面就会突破浏览器的限制;其次, 启用多个静态资源服务器,可以减轻主服务器的压力。
四、vue面试题
1. 移动端有哪些常见的问题?怎么解决的?
- H5页面窗口自动调整到设备宽度,并禁止用户缩放页面。
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimumscale=1.0,maximum-scale=1.0,user-scalable=no">
2. 说说图片懒加载的原理?实际开发中用过哪些图片懒加载的插件?
- img 标签在加载图片的时候, 是通过请求 src 属性所指向的文件来加载图片的, 那如果 img 标签本身没有 src 属性的话, 那么 img 标签在渲染的时候, 就不会加载图片.所以图片懒加载的原理就是将 img 标签的 src 属性给暂时先改成一个自定义的属性, 这样页面已加载就会不去加载图片, 当 img 标签所在区域进入屏幕可视区域后, 从存放图片路径的自定义属性中获取图片地址,并动态的设置给对应 img 标签的 src 属性, 这样浏览器就会自动帮助我们去请求对应的图片资源, 也就实现了所谓的图片懒加载.图片懒加载的插件有很多, 大部分是基于 jquery 的, 比如jquery.lazyload。 当然 vue 的中也有实现了图片懒加载的插件, 比如 vue-lazyload, vue 的组件库中也有图片懒加载的组件。
3. 移动端点击事件会有多少秒的延时?什么原因造成的?如何解决?
- 移动端的点击事件会有 300ms 的延时;是因为浏览器为了保留双击缩放的功能所造成的,早期浏览器都有一
个双击缩放的功能, 在用户点击一次以后, 浏览器会等待第二次点击,如果用户在 300ms 内进行了第二次点击, 那么浏览器就会执行缩放的功能, 如果 300ms 内没有再次点击, 则会当做单击事件处理;
解决方案:使用touch 触摸事件来模拟点击事件;使用fastclick 插件来解决;静止页面缩放功能。
4. Js 是如何实现异步操作的?
- Js 虽然是单线程的, 但是浏览器是多线程的, js 中的异步操作基本都是由浏览器提供的子线程来完成的。
5. 分别介绍下 MVC, MVVM, MVP 这三种设计模式?
- MVC 是后端语言的一种设计模式, 主要是实现对代码分层, M(model) 数据模型层, 主要负责操作数据库; V(view)视图层, 主要负责进行界面展示, 可以认为前端的 html,css,js 充当的就是视图层; C(controller) 业务控制层, 主要负责控制具体的业务逻辑, 负责将 model 数据层的数据交给 view 视图层进行展示。
- MVVM 是前端的一种设计模式, vue 就是基于这种模式来设计的, 是从MVC 演变过来的. M(model)数据层, 主要负责数据和方法的初始化;V(view)视图层, 可以认为 html,css 充当的就是视图层的角色; VM(viewmodel)视图模型层, 负责连接数据层和视图层, 将数据层的数据交给视图层展示, 将视图层的行为传递给数据层。
- MVP 也是从后端的 MVC 设置模式中演化过来的, 主要应用于安卓开发中。M(model) 数据层, V(view) UI 逻辑;P(Presenter)业务逻辑。
6. vue 中如何封装一个组件?
- 首先定义一个后缀名为.vue 的文件. 文件内部还是三部分组成,template 模板部分, script 逻辑部分, style 样式部分. 这三部分是组件的核心部分, 组件需要哪些结构, 在模板部分书写, 需要什么样的外观样式, 通过 style 部分书写, 有哪些行为在 script 部分书写。一定要在script 部分使用 es6 模块化的导出语法(export default{}), 进行导出.。然
后在需要调用组件的地方使用 es6 模块化导入语法导入即可, 组件需要哪些参数, 直接在调用的部分进行传递即可。主要逻辑还是在组件中完成。
7. 说说 Vue 路由的使用步骤?
- 第一步:下载路由模块 vue-router。
- 第二步:创建路由对象。
- 第三步:配置路由规则。
- 第四步:将路由对象注册为 vue 实例对象的成员属性。
8. 谈谈对于 MVVM 的理解?
- MVVM 由三部分组成M(model 数据层), V(view 视图层),VM(view-model) 视图模型层. 是一种框架的设计思想,vue 就是基于 mvvm 来设计的。其中 M(model) 层 是 负 责 初 始 化 数 据 ,V(view) 只 负 责 页 面 展示,VM(view-model)用来连接 view 层和 model 层, 将数据层的数据传递一个视图层进行展示, 将视图层的操作传递到数据层进行持久化。
9. Vue 的生命周期?
- 创建阶段: 只执行一次。beforeCreate(开始进行一些数据和方法的初始化的操作, data 中的数据和 methods 中的方法还不能用),
created(已经完成数据和方法的初始化, data 中的数据和 methods 中的方法可以使用了)。 - 挂在阶段:beforeMount(开始渲染虚拟 DOM),mounted(已经完成了虚拟 DOM 的渲染, 可以操作 DOM 了, 只执行一次)。
- 运行阶段: 执行多次。beforeUpdate(data 中的数据即将被更新, 会执行多次),updated(data 中的数据已经更新完毕, 会执行多次) 。
- 销毁阶段: 只执行一次,beforeDestroy(vue 实例即将销毁, 此时 data 中的数据和 methods 中的方法依然处于可用状态)。destroyed(vue 实例已经销毁, 此时 data 中的数据和 methods 中的方法已经不可用)。
10. Vue 中有几种路由模式?
- Vue中的路由模式有两种:hash,history; 默认是hash模式; 可以在创建路由对象的时候, 使用 mode 属性来切换路由模式,const router=new Router({mode:’history’})。
11. Vue 路由导航守卫是什么, 以及应用场景?
- 路由守卫是在页面进行路由跳转的时候做一些处理, 比如拦截,vue-router 中提供了下面几种路由导航守卫:
- 全局前置守卫
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// from 从里来
// to 到哪里去
// next 是否要放行
})
- 全局后置钩子
router.afterEach((to, from) => {
// ...
})
- 路由独享守卫: 在声明路由的时候, 针对特定路由的钩子函数。
const router = new
VueRouter({ routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
12. Vue 路由模块中$route
和$router
的区别?
1. $route
中存储的是跟路由相关的属性(如$route.params,$route.query)
;
2.$router
中存储的是和路由相关的方法(如$router.push(),$router.go())
。
13. vue 中 v-for 指令循环遍历中 key 属性的作用?
- Key 属性的作用是在数据层和视图层之间建立一一对应关系, 方便后期对页面进行局部更新. 如果某一条数据发生改变, 只更新当前数据对应的 DOM 元素。
14. Vue 和 react 有哪些不同的地方?
- Vue 实现了双向数据绑定(数据<=>界面)。
- react 仅仅实现了单项数据流(数据层=>界面层)。
- vue 中提供了指令, react 中没有指令的概念。
- vue 中使用插值表达式在进行数据渲染, react 中使用 jsx 进行数据的渲染。
15. 列举 Vue 中常用的指令
- v-model:实现双向数据绑定;
- v- bind: 绑定属性;
- v-on:注册事件;
- v-html: 设置标签内容(允许内容 html)。
- v-text: 设置标签的内容(不允许包含 html) 。
- v-clack: 解决插值表达式闪烁问题。
- v-for: 循环遍历数组或对象。
16. Vue 中如何解决插值表达式闪烁问题?
- 使用 v-html 或 v-text 替代插值表达式;
- 使用 v-clack 解决插值表达式闪烁,第一步:声明属性选择器[v-clack]{display:none} ;第二步:在插值表达式所在标签添加属性 v-clack。
17. Vue 路由中如何实现通过锚点值的改变切换组件?
- 通过监听 hashchange 事件, 具体如下:
window.addEventListener('hashchange',function(){
console.log('hash change');
});
18. Vue 中如何动态添加一个路由规则?
- 使用 router.addRoutes([{path:’’,component:’’}])
什么是路由懒加载? 路由懒加载有什么好处? 如何实现路由懒加载?
- 路由懒加载是指通过异步的方式来加载对应的路由组件(默认情况是将所有的组件全部加载并打包)。
- 路由懒加载的好处: 可以提高页面的加载速度, 尤其是首页的加载速度(因为使用了懒加载后, 加载首页的时候, 就不需要加载其他页面对应的组件, 在需要的时候再加载)。
import Vue from 'vue';
import Router from 'vue-router';
// 异步导入组件
// 异步加载方式一
const List = resolve => require(['@/components/list'], resolve);
// 异步加载方式二
const Detail = () => import(/* webpackChunkName: "group-master" */
'@/components/detail')
Vue.use(Router);
export default new Router({
// 路由规则
routes:[
{path:'/list',component:List},
{path:'/detail',component:Detail}
],
// 路由模式: 默认 hash, 可选值 hash(如#/index)|history(/index)
mode:'history'
});
19. Vue 中有哪些内置的组件?
- component, slot, transition, transition-group, keep-alive
<!-- 动态组件由 vm 实例的属性值 `componentId` 控制 -->
<component :is="componentId"></component>
<!--tansition 动画组件的使用-->
<transition>
<div v-if="ok">toggled content</div>
</transition>
20. vue 实例中有哪些属性?
- vm.$data 可以获取 vm 实例对象 data 中的数据;
- vm.$props 可以获取 vm 组件接收到的 props 对象数据;
- vm.$el 可以获取 vm 实例对象的根 dom 元素;
- vm.$refs 可以获取 vm 实例中注册过 ref 特性的所有 dom 元素和组件实例。
21. Vue.use(plugin)的作用是什么, 使用的时候需要注意什么问题?
- Vue.use 的作用是安装一个 Vue 插件, 该方法需要在调用 new Vue()之前被调用。
22. vm.$nextTick(fn)的作用是什么?
- 延迟某个操作的执行, 直到 dom 更新以后在执行。
<body>
<div id="app"><h1 ref="h1">{{title}}</h1></div>
</body>
<script>
var vm = new
Vue({ el: '#app',
data: {
title: '这是一个标题'
}
created: function () {
this.$nextTick(() => {
// 在 created 里直接操作 ref 会报错
this.$refs.h1.innerHTML = '这是更新以后的标题';
});
}
})
23. vue 中的混入(mixin)有什么作用?
- 混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
24. 如何开发一个 vue 插件?
- Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是Vue 构造器,第二个参数是一个可选的选项对象。
// 定义插件
const myPlugin={ install:(Vue,options)=>{
// 1. 添加全局方法或属性
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局指令
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
})
// 3. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
// 4. 注入组件选项(混入)
Vue.mixin({
created: function () {
}
})
// 5. 注册全局组件
Vue.component('myCompent',{
template:'<h1>loading...</h1>'
});
}
}
export default myPlugin;
// 调用插件
Vue.use(myPlugin,{})
25. 什么是 ssr? 如何实现 ssr?
- ssr 是全拼(server side rendering) ,中文意思, 服务端渲染, 让页面的渲染在服务端完成, 生产环境必须部署nodeJS 的环境, 因为服务端渲染必须借助 nodeJS 来完成. vue 中可以使用 nuxt 框架实现服务端渲染。
26. 什么是虚拟 DOM, 使用虚拟 DOM 有什么优势?
- 虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中,当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把所记录的差异应用到步骤 1 所构建的真正的 DOM 树上,视图就更新了。
27. 商城的购物车是怎么实现的?
- 商城购物车一般会写在本地存储,比如cookie 或者localStorage 中,会采用数组格式的字符串来存储,主要会存储商品id, 商品名称, 商品价格, 商品数量等信息(当然商品价格等敏感信息后期还是以后端为准, 此处存储只是为了方便在页面展示), 如果过要考虑兼容问题, 建议存储在 cookie 里(因为 localStorage 低版本的浏览器不支持).如果不考兼容问题, 使用 localStorage 性能会更好. 购物车可以在用户未登录的状态就可以添加, 也可以在用户登录以后再添加, 这个完全取决于具体业务场景。
28. 前后端分离的项目如何实现登录状态的保持?
- 前后端分离的项目一般会使用 token 实现登录状态保持。token 其实就是一个随机字符串, 当用户在登录页面输入账号和密码后, 前端将账号密码发送给后端, 后端校验完账号和密码后, 会生成一个随机的不重复的字符串(即 token), 并将其响应给前端, 前端拿到该 token 后, 需要在客户端进行持久化(一般会写在 localStorage 或者sessionStorage 中, 如果是 SPA 会存储在 sessionStorage 中, 如果是MPA 则储存在 localStorage 中), 那么下次在向后端数据接口发送请求的时候, 一般需要将 token 一并发送给后端数据接口, 后端数据接口会对token 进行校验, 如果合法则正常响应请求, 如果不合法, 则提示未登录. 前端则根据本地存储中是否存在 token 判断用户是否处于登录状态。
29. 前后端分离开发的后台管理系统一般如何实现权限管理?
- 首先某个角色有哪些权限肯定是事先配置好的, 并且存储在了数据库里。当某个账号登录后, 后端数据接口则需要返回该账号对应角色的权限列表, 前端则需要根据该权限列表, 动态渲染管理系统的导航, 当然后端数据接口也会做二次权限校验(当某一个角色请求一个自己没有的授权的数据接口或页面的时候, 后端数据接口也不会正常响应)。
30. Vue 开发中如果由于某种特殊原因数据更新之后, 页面层没有同步更新, 该如何处理?
- 调用 vm.$forceUpdate()方法强制刷新页面, 该方法可以迫使 Vue 实
例重新渲染
五、React面试题
1. 简单介绍下 react 中的 diff 算法?
- 把树形结构按照层级分解,只比较同级元素。给列表结构的每个单元添加唯一的 key 属性,方便比较。React只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty。到每一个事件循环结束, React 检查所有标记 dirty 的component 重新绘制。选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高diff 的性能。
// 创建对比函数
function updateChildren(vnode, newVnode) {
var children = vnode.children || []
var newChildren = newVnode.children || []
children.forEach(function (childrenVnode, index) {
// 首先拿到对应新的节点
var newChildVnode = newChildren[index]
// 判断节点是否相同
if (childrenVnode.tag === newChildVnode.tag) {
// 如果相同执行递归,深度对比节点
updateChilren(childrenVnode, newChildVnode)
} else {
// 如果不同则将旧的节点替换成新的节点
repleaseNode(childrenVnode, newChildVnode)
}
})
}
// 节点替换函数
function repleaseNode(vnode, newVnode)
{ var elem = vnode.elem
var newEle = createElement(newVnode)
}
2. 什么是 Redux?
- Redux 是一个状态管理工具, 不仅可以在 react 中使用, 也可在其他框架中使用, 甚至可以脱离框架本身使用. redux 中有几个核心的组成部分:
- store 存储数据的对象,必须通过 createStore 方法来创建;
- action 更新数据的规则, 必须有一个属性 state, 值必须是字符串;
- reducer 更新数据的函数, 需要传入 state 状态数据和 action 更新规则。在 react 中使用 redux 的时候, 一般会使用 react-redux 来简化使用步骤。
3. React 有哪些常用的组件库?
- PC 端组件库: element-ui(饿了么推出的前端组件库), ant-design(阿里巴巴的前端组件库, 几乎覆盖了三大框架); zent(有赞推出的 PC 端组件库)
4. React 中如何操作 DOM?
- 在需要进行 dom 操作的标签上设置一个 ref 属性, 保证值不要重复,后期在js 部分可以通过
this.refs.属性名
来获取标签的虚拟dom 对象。
5. 什么是高阶组件(HOC)?
- 函数的返回值是一个函数, 我们称之为高阶函数. 同理一个组件返回值如果还是一个组件, 那么就称之为高阶组件. redux 中提供的connect 就是一个高阶组件。
6. React 中调用 setState 后发生了什么?
- 在代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
7. React 中状态 state 和属性 props 有什么不同?
- state 是组件的私有数据, 可读可写, props 是只读属性, 一般来自外部(比如父组件)。
8. React 中有几种创建组件的方式?
- 通过函数的方式创建组件, 此种方式创建的组件为无状态组件(不常用);
- React.createClass();通过 class 类的方式创建组件(须继承 React.Component), 实际开发中使用此种方式。
9. React 中的组件按照职责不同, 可以分为几种类型?
- 根据组件的职责通常把组件分为 UI 组件和容器组件;UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑;两者通过 React-Redux 提供 connect 方法联系起来。
10. 类组件(Class component)和函数式组件(Functional component)之间有何不同?
- 类组件不仅允许你使用更多额外的功能,如组件自身的状态和生命周期钩子,也能使组件直接访问 store 并维持状态;当组件仅是接收props,并将组件自身渲染到页面时,该组件就是一个 ‘无状态组件(stateless component)’,可以使用一个纯函数来创建这样的组件。这种组件也被称为哑组件(dumb components)或展示组件。
11. 说说 react 的生命周期函数?
- 初始化阶段:getDefaultProps:获取实例的默认属性getInitialState:获取每个实例的初始化状态componentWillMount:组件即将被装载、渲染到页面上render:组件在这里生成虚拟的 DOM 节点componentDidMount:组件真正在被装载之后。
- 运行中状态:componentWillReceiveProps:组件将要接收到属性的时候调用shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回 false,接收数据后不更新,阻止 render 调用,后面的函数不会被继续执行了)componentWillUpdate:组件即将更新不能修改属性和状态render:组件重新描绘componentDidUpdate:组件已经更新。
- 销毁阶段:componentWillUnmount:组件即将销毁。
12. react 性能优化可以使用哪个生命周期函数?
- shouldComponentUpdate 这个方法用来判断是否需要调用 render 方法重新描绘 dom。因为 dom 的描绘非常消耗性能,如果我们能在shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能。
13. 应该在 React 组件的何处发起 Ajax 请求?
- 在 React 组件中,应该在 componentDidMount 中发起网络请求。这个方法会在组件第一次“挂载”(被添加到 DOM)时执行,在组件的生命周期中仅会执行一次。更重要的是,你不能保证在组件挂载之前 Ajax 请求已经完成,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。在 componentDidMount 中发起网络请求将保证这有一个组件可以更新了。
14. 自定义的 react 组件首字母为什必须要大写?
- Babel 在对 jsx 代码进行编译的时候, 如果首字母大写, 就把其当做react 组件编译, 编译成 js 对象; 如果首字母小写,则认为是一个普通的 html 标签, 会解析成普通字符串。
15. setState 什么时候是同步,什么时候是异步?
- 这里的“异步”不是说异步代码实现. 而是说 react 会先收集变更,然后再进行统一的更新。setState 在原生事件和 setTimeout 中都是同步的。在合成事件和钩子函数中是异步的.。在 setState 中, 会根据一个isBatchingUpdates 判断是直接更新还是稍后更新, 它的默认值是false。但是React在调用事件处理函数之前会先调用batchedUpdates 这个函数会将isBatchingUpdates 设置为 true. 因此, 由 react 控制的事件处理过程,就变成了异步(批量更新)。
六、微信小程序开发?
1. 微信小程序目前有几种主流的开发模式?
- 微信官方:原生方式;
- 第三方公司:uni-app。
2. 简单介绍微信小程序的开发过程?
- 首先得注册以为微信小程序, 因为小程序开发过程中需要一个 appid; 其次下载腾讯官方的开发者工具(开发者工具必须使用个人微信登录),小程序只能运行在开发这工具或者微信应用内部;创建应用, 填入申请的 appid, 即可快速生成小程序的项目结构。
3. 简单描述微信小程序的生命周期?
- 小程序的生命周期分为应用生命周期和页面生命周期。
- 应用生命周期:
onLaunch: 应用启动, 只执行一次;
onShow: 应用切换到前台;
onHide: 应用切换到后台模式;
noError: 运行阶段出现错误;
onPageNotFound: 找不到页面 - 页面生命周期:
onLoad: 页面开始加载;
onReady: 页面加载完毕;
onShow: 页面进入焦点状态;
onHide: 页面进入后台状态
七、Typescript 和 javascript 的区别?
1. Typescript 中有哪些数据类型?
- number(数值), string(字符型), boolean(布尔), object(对象),undefined(未定义), null(空性), any(任意类型), never, 元组, 枚举, 数组。
2. Typescript 和 javascript 的区别?
- Typescript 是 javascript 的一个超集, 是 es6 的实现, 支持所有 es6 的语法, Typescript 只是在开发过程中编写的一种中间语言, 浏览器并不能直接解析 Typescript, 上线以后需要将 Typescript 转换成 javascript。
八、代码版本控制工具
1. git 中有哪些常用的命令?
初始化仓库: git init
添加暂存区: git add 文件名
提交到本地仓库: git commit -m ‘注释‘
推送到远程仓库: git push 仓库地址 分支名称
拉取远程仓库代码: git pull
克隆仓库: git clone 仓库地址创
建分支: git branch 分支名称切
换分支: git checkout 分支名称查
看分支: git branch
合并分支: git merge 分支名称查
看日志: git log (git log --oneline)
查看所有日志: git reflog
版 本 回 退 : git reset --hard 版 本 号 (commit-id 可 以 通 过 git log
–oneline 获取)
2. git 和 svn 有什么不同?
- git 是一个分布式仓库管理系统, 每个人本地都有一个本地仓库,svn 是一个集中式仓库管理系统, 仓库只有一个。svn 一般需要服务端给每个人分配账号和密码, git 是使用 ssh 公钥/秘钥对来区分不同程序员的。
3. 在线 Git 代码托管平台有哪些?
github(https://www.github.com),
gitlab(https://www.gitlab.com),
gitee(https://www.gitee.com),
coding(https://coding.net),
腾讯云开发者平台(https://dev.tencent.com),
bitbucket(https://bitbucket.org/product/)