请稍等...正在玩命加载中......

前端学科独家面试宝典


免责声明:该文来自传智播客,仅供学习使用,禁止用于商业用途,禁止转载,否则追究法律责任!

文中难免有错误,获取完整版pdf文档关注微信公众号“51学代码”,回复“前端面试”获取资料。

前端学科独家面试宝典
前端基础 
HTML(5)
1. Html5 新增那些标签? 
2. 布局标签:
header,section,footer,article,aside 
表单标签: datalist,
input:type=’week|date|time|datetime|number|search|url|tel| 
color|email|range’
多媒体标签: audio(音频), video(视频)
其他标签: progress(进度条),meter(度量器) 
补充:
Html5 新 属 性 : 
hidden( 隐 藏 元 素 ),required( 必 填 ),minlength( 最 小 长 度),maxlength(最大长度),pattern(正则表达式),placeholder(提
示文本),autocomplete(自动填充),autofocus(自动获取焦点)
3. 行内元素和块级元素的具体区别是什么?
块级元素独占一行页面空间, 不会和其他元素共享一行页面空间; 
行内元素可以和其他非块级元素(行内,行内块)共享一行页面空间.
4. 列举几个块级标签和行内标签?
块级标签:div,p,h1~h6,section,header,footer 
行内标签:span,em(i),strong(b),u,em(i),a
5. 行内元素的 padding 和margin 可设置吗?
行内元素设置水平方向的padding 和margin 是可以生效,但是设置垂
直方向的padding 和margin 虽然看起来对标签起作用,但实际并没有
对周围元素产生任何影响, 所以行内元素设置垂直方向的 padding 
和 margin 是无效的.
6. 简述 readyonly 与 disabled 的区别
readyonly 是设置表单元素为只读状态;
disabled 是设置表单元素为禁用状态.
7. 哪些标签都存在伪元素?
大部分容器标签(大部分双标签)都有伪元素, iframe 没有伪元素; 
大部分单标签都没有伪元素, 但是 img 有伪元素
8. 伪元素可以使用 js 来操作吗?
js 不可以操作伪元素
9. Html5 的网页为什么只需要写<!DOCTYOE HTML>?
HTML 4.01 中的 doctype 需要对 DTD 进行引用,因为 HTML 4.01 基 于 SGML。而 HTML 5 不基于 SGML,因此不需要对 DTD 进行引用,
但是需要 doctype 来规范浏览器的行为。其中,SGML 是标准通用标
记语言,简单的说,就是比 HTML,XML 更老的标准,这两者都是由 SGML 
发展而来的,HTML5 不是的。
CSS(3)
10.px em rem 这三中长度单位的区别?
px 是一个绝对单位;em 和 rem 是一个相对单位, em 参考的是当前元
素的字体(font-size) 大小, 参考的是页面根元素 html 的字体
(font-size)大小.
11. CSS3 新增伪类有那些?
p:first-of-type 选择属于其父元素的首个<p>元素。
p:last-of-type 选择属于其父元素的最后一个<p>元素。
p:nth-child(2)选择属于其父元素的第二个子元素。
p:nth-type-of(2)选择属于其父元素的第二个子元素 p。
:enabled、:disabled 控制表单控件的禁用状态。
:checked,单选框或复选框被选中。
11.谈谈 css 选择器优先级顺序以及判定标准? 
优先级从低到高:
通配符选择器<标签选择器<类选择器(属性选择器)<ID 选择器; 
行内样式<使用!important 修饰的属性优先级最高;
如果两个选择器(属性完全相同)同时命中一个元素, 并且权重一样, 
则书写顺序会影响优先级, 后一个选择器的属性会覆盖前一个选择
器中相同的属性.
12. position 几 个 属 性 的 作 用 ? position
的常见四个属性值: relative,absolute,fixed,static。一般都要
配合"left""top""right"以及"bottom" 属性使用。
1static:默认位置,(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 属性的元素在标准流中不占位置。
13. position 设 置 为 absolue 和 fixed 有 什 么 区 别 ? 
absolute 是绝对定位, 绝对定位参考的是有明确定位的父元素, 如
果直接父元素没有明确定位会一直向上查找,如果父元素都没有明确
定 位 , 则 参 考 body 标 签 ; 
fixed 是固定定位, 参考对象是浏览器.
14.在一个页面中给多个元素设置相同的 id, 会导致什么问题?
会导致通过 js 获取 dom 元素的时候, 只能获取到第一个元素, 后面
的元素都无法正常获取.
15.用伪类实现一个上三角?
<div class=’triangle_border_up’></div>
.triangle_border_up{ bor
der:20px solid red; 
border-top:0;
border-left:20px solid transparent; 
border-right:20px solid transparent; 
width:0px; }
[在此处键入]
.parent{
background: #DDD; 
width: 400px; 
height: 400px; }
.son{
position: relative; 
background: pink; 
width: 200px; 
height: 200px;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
16.怎么让一个不定宽高的 div,垂直水平居中?
方案一:transform
方案二:flex 弹性布局
方案三:绝对定位
.parent{
display: flex;
justify-content: center; 
align-items: center; 
background: #DDD;
width: 400px;
height: 400px; }
.son{
background: pink; 
width: 200px; 
height: 200px; }
.parent{
[在此处键入]
.clear:after{ content
:''; display:block; 
overflow:hidden; 
visibility:hidden; 
clear:both; }
17.清除浮动有哪些常用的方式?
额外标签法: 在浮动元素的最后添加一个块级标签, 给其设置一个
clear:both 的属性 (缺点:会在页面上产生很多空白标签); 
给浮动元素的父元素设置高度:(缺点:不太灵活);
给浮动元素的父元素设置 overflow:hidden; 
使用伪元素法:(推荐使用)
18.让两个块级元素在一行显示有哪些做法?
position: relative; 
background: #DDD; 
width: 400px; 
height: 400px; }
.son{
position: absolute; 
top:0;
bottom:0; 
left:0; 
right:0;
background: pink; 
width: 200px; 
height: 200px; 
margin: auto; }
[在此处键入]
设置显示模式:display:inline|inline-block;
flex 布局: 给父元素设置 display:flex; 
使用浮动
19.如何设置一个元素在垂直方向居中?
首先不考虑代码的灵活性, 可以使用 margin 外边距或者 padding 内
边距来实现元素在垂直方向居中显示.具体可以给父元素设置一个垂直方向的
padding 内边距; 也可以给需要垂直居中的子元素设置垂直方向的外
边距.其次如果这个需要垂直居中的元素是一个单行文本, 则可以使
用行高等于标签高度的方式来实现.也可以使用 css3 中的
flex 布局, 使用 align-items:center 设置元素在侧轴(垂直方向)居
中对齐.也可以使用绝对定位的方式, 设置元素在相对定位的父元素中
垂直对齐.
20.说说图片懒加载的原理?实际开发中用过哪些图片懒加载的插件?
img 标签在加载图片的时候, 是通过请求 src 属性所指向的文件来加
载图片的, 那如果 img 标签本身没有 src 属性的话, 那么 img 标签在
渲染的时候, 就不会加载图片.所以图片懒加载的原理就是将 img 标签 的 src 属性给暂时先改成一个自定义的属性, 这样页面已加载就会
不去加载图片, 当 img 标签所在区域进入屏幕可视区域后, 从存放
图片路径的自定义属性中获取图片地址,并动态的设置给对应 img 
标签的 src 属性, 这样浏览器就会自动帮助我们去请求对应的图片
[在此处键入]
资源, 也就实现了所谓的图片懒加载.图片懒加载的插件有很多, 大
部分是基于 jquery 的, 比如 jquery.lazyload. 当然 vue 的中也有
实现了图片懒加载的插件, 比如 vue-lazyload, vue 的组件库中也有
图片懒加载的组件.
21. css3 新增了那些新特性? 
媒体查询(@media);
transfrom 系列:translate 平移, scale 缩放,rotate 旋转
动画(animate);
过渡效果(transition);
flex 弹性(伸缩)布局;
盒模型计算方式 box-sizing:border-box; 
线性渐变(linear-gradient),径向渐变;
伪元素, 文字阴影(text-shadow), 边框阴影(box-shadow), 圆角
(border-radius)
22. display:none 和visibility:hidden 的区别?
display:none 隐藏元素后,不占位; 
visibility:hidden 隐藏元素后占位.
23. Less 是什么?
Less 是一种 css 预处理语言, 在 less 中可以定义一些变量和表达式
10
[在此处键入]
以及使用嵌套语法; less 中使用@定义变量(@baseColor:pink);期可以通过一些编译工具(less)将 less 编译成浏览器能直接识别的
css 样式. 所以 less 只是在开发阶段使用的一种中间语言, 使用
less 的目的是提高开发效率以及提高代码的可维护性.
24. Scss 是什么?(sass)
scss 是一种 css 预处理语言, 在 less 中可以定义一些变量和表达式
以及使用嵌套语法; scss 中使用$定义变量($baseColor:pink);期可以通过一些编译工具(node-sass)将 less 编译成浏览器能直接
识别的 css 样式. 所以 scss 只是在开发阶段使用的一种中间语言, 
使用 scss 的目的是提高开发效率以及提高代码的可维护性.
25. Stylus 是什么?(.styl)
stylus 是一种 css 预处理语言, 在 stylus 中可以定义一些变量和表
达式以及使用嵌套语法(stylus 中是使用缩进的语法表示嵌套关系); 
后期可以通过一些编译工具(stylus)将 stylus 编译成浏览器能直接
识别的css 样式. 所以stylus 只是在开发阶段使用的一种中间语言, 
使用 stylus 的目的是提高开发效率以及提高代码的可维护性.
11
[在此处键入]
JavaScript
JavasSript 基础 
26. js 中有哪些数据类型
int( 数 值 ), string( 字 符 串 ), boolean( 布 尔 ), null(),
undefined(未定义), object(对象)
27. typeof(typeof())instanceof 的区别?
typeof 可以判断变量的数据类型,返回值是字符串;
a instanceof b 是判断 b 是不是在 a 的原型链上, 也可以实现判断
数据类型, 返回值为布尔.
28.怎么判断两个对象相等? 
先判断俩者是不是对象;
再判断俩个对象的所有 key 值是否相等相同;
最后判断俩个对象的相应的 key 对应的值是否相同
29. js 中函数有哪些定义方式
函数声明:function fn(){}
函数表达式:var fn=function(){}
构造函数:var fn=new Function(‘ 参数 1,’ 参数 2,’ 函数
体’)
12
[在此处键入]
30. js 中函数有哪些调用形式?
普通函数,对象的方法,事件处理函数,构造函数,回调函数
31."==""===" 的区别?
==只会对值进行比较,===不仅会对值进行比较,还会对数据类型进行
比较.
32.js 中的常用内置对象有哪些?并列举该对象的常用方法?
Math(数学相关);Date(日期相关);Array;Object
33.列举和数组操作相关的方法
push:将元素添加到数组的末尾, 返回值是数组长度
pop:将数组最后一个元素弹出, 返回值是被弹出的元素
unshift:在数组的开头插入一个元素,返回值是数组的长度
shift:将数组第一个元素弹出,返回值是被弹出的元素
splice(index,len):删除数组中指定元素
concat:连接数组
reverse: 翻转数组
34.列举和字符串操相关的方法
substr(start,len)/substring(start,end): 截取字符串
13
[在此处键入]
slice:从数组会字符串中截取一段
indexOf/lastIndexOf:查找某一个字符是否存在于另外一个字符串
中, 存在则返回索引, 不存在则返回-1;indexOf 是从前向后顺序查
找;
lastIndexOf:是从后向前查找
replace:替换字符串特定的字符
toUpperCase:将字符串转成大写
toLowerCase:将字符串转成小写
charAt:获取字符串中指定索引的字符
35.document.write 和 innerHTML 的区别?
document.write 是指定在整个页面区域的内容, innerHTML 是指定某
一个元素的内容.
36.分别阐述 split(),slice(),splice(),join()?
split 可以使用一个字符串切割另外一个字符串, 返回值是数组;
slice 可以从数组中截取一部分(字符串对象也有 slice 方法);
splice(index,len)可以删除指定的数组元素;
join 可以将数组元素使用特定的连接符拼接成字符串
37.例举 3 中强制类型转换和 2 中隐式类型转换?
强制转换:
14
[在此处键入]
转化成字符串 toString() String() 转换成数字 Number()parseInt()parseFloat(); 
隐式转换:
转换成布尔类型 Boolean() 隐式拼接字符串
例子 var str = "" + - / % ===
38.如何判断一个变量 foo 是数组?
Javascript 高级 
39.什么是原型对象?
每一个构造函数都有一个 prototype 的属性, 这个属性的值是一个
对象, 这个对象就叫做构造函数的原型对象; 一般建议将构造函数
的成员属性绑定在原型对象 prototype 上, 因为原型对象 prototype 
身上的属性默认可以通过实例对象访问到; 这样做可以保证在每次
通过 new 关键字创建实例对象的时候, 这些方法不会被重复在内存
中创建.
40.什么是原型链?
foo instanceof Array; 
foo.constructor == Array; 
Array.isArray(foo)
Object.prototype.toString.call(foo)=="[object Array]"
15
[在此处键入]
function 
Person(name,age,gender){ this.
name=name||''; 
this.age=age||''; 
this.gender=gender||''; }
Person.prototype.sayHi=function(){ conso
le.log('I am '+this.name);
}
每个构造函数都有一个 prototype 属性, 即原型对象, 通过实例对
象的 proto 属性也可访问原型对象;而原型对象本质也是一个对
象, 是对象就有自己的原型对象, 最终形成的链状的结构称为原型
链.
41.什么是构造函数?
构造函数本质也是一个函数, 只不过这个函数在定义的时候首字母
一般需要大写; 构造函数调用的时候,必须通过一个 new 关键字来调
用; 我们一般不直接使用构造函数, 而是使用构造函数创建出来的
实例对象. 构造函数是 js 面向对象的一个重要组成部分.
42.js 中实现继承的方式?
ES6 之前官方并没有提供一种实现继承的语法, 所以大部分继承方式
都是程序员通过代码在模拟.常见的继承方式有以下几种:
原型继承;
借用构造函数继承; 
组合继承;
16
[在此处键入]
function fn(){
var a=100;
return 
function(){ retu
rn a;
ES6 之后使用 extends 关键字实现继承(class Student extends 
Person{})
43.什么是闭包, 有什么作用, 使用的时候需要注意什么?
闭包是一个跟函数相关的概念,表现形式是一个父函数内部,嵌套了
一个子函数, 子函数直接或间接的被返回给外部作用域, 并且子函
数中会使用到父函数局部作用域中的变量.当我们在外部调用这个子
函数的时候, 就会发生闭包现象.
闭包的作用:闭包可以延展一个函数的作用域
注意事项:不能滥用闭包, 会导致内存泄漏
function Student(name,age,gender,score){
// 通过构造继承属性
Person.call(this,name,age,gender);
}
// 通过原型继承,继承方法
Student.prototype=new Person();
// 修改 constructor 的指向
Student.prototype.constructor=Student;
// 动态添加成员方法
Student.prototype.printScore=function(){ 
console.log('my score is '+this.score);
}
// 创建 Student 实例对象
var s1=new Student('zs',30,'男',90); 
s1.sayHi();
s1.printScore();
17
[在此处键入]
44.什么是内存泄漏, 那些操作会引起内存泄漏?
内存泄漏是指本应该被垃圾回收机制回收的内存空间由于某种特殊
原因没有及时被回收, 称之为内存泄漏. 滥用全局变量和滥用闭包
都会导致内存泄漏.
45.什么是预解析?
JS 代码在执行之前,解析引擎会对代码进行一个预先的检查, 主要会对
变量和函数的声明进行提升, 将变量和函数的声明提到代码的最前 面.变量只提升声明, 不提升赋值.
46.说说你对 this 关键字的理解
this 在不同的场景下指向不太一样, 主要分为一下几种情况: 
普通函数中指向全局 window;
对象的成员方法中指向该方法的宿主对象; 
构造函数中指向 new 出来的实例对象;
事件处理函数中指向事件源; 
回调函数中指向全局 window
47. call/apply/bind 的区别
}
var fn1=fn(); 
fn1();
18
[在此处键入]
这三个方法都是函数这个特殊对象的方法,通过这三个方法都可以改
变函数内部 this 的指向.
不同点:
call 和apply 会调用一次函数, 而 bind 不会调用函数, 只会在内存
中创建一个函数的副本(修改过 this 指向的函数).
call 从第二个参数开始需要一个参数列表,
apply 第二个参数需要是一个数组
48. caller 和callee 的区别是什么?
函数 fun.caller 返回调用 fun 的函数对象,即 fun 的执行环境,如
果 fun 的执行环境为 window 则返回 null;
Callee 是函数的 arguments 这个特殊对象的一个属性, 指向函数本
身.
49. new 操作符具体干了什么呢? 
第一步创建一个空对象;
第二步将 this 指向空对象;
第三步动态给刚创建的对象添加成员属性; 
第四步隐式返回 this
代码分析 
50. 下面代码的执行结果是什么?
19
[在此处键入]
依次输出: hello one,hello four,hello three,hello two
51. 下面代码执行结果是什么?
执行结果:
输出 {id: 1, name: "test"}
分析过程:
对象是一种引用数据类型, 简单的 b=a 只是把 a 在内存中的地址赋值
给了 b, 所以修改 b 会影响 a.
52. 下面代码执行结果是什么?
var 
hellword=(function(){ con
sole.log('hello one'); 
setTimeout(function(){
console.log('hello two');
},100);
setTimeout(function(){ consol
e.log('hello three');
},0);
console.log('hello four');
}());
var a={
id:10
}b=a; 
b.id=1; b.name='test';
console.log(a);
var length=10; 
function fn(){
console.log(this.length);
20
执行结果:
在控制台输出 10,2
分析过程:
fn(); 此时 this 指向 window, 所以 this.length=10;
arguments[0]()中的 this 永远指向 arguments, 而 arguments 本身有一
个 length 属性, 就是参数的个数.
53. 下面代码执行完毕, 浏览器依次弹出什么?
执行结果:
依次弹出: number; number,undefined,number
分析过程:
自调用函数会开辟一个局部作用域, var a=b=5 这句代码 var 只会修饰
}
var 
obj={ lengt
h:5,
method:function(fn){ f n(); 
arguments[0]();
}}
obj.method(fn,1);
(function 
test(){ var 
a=b=5; 
alert(typeof a); 
alert(typeof b);
})()
alert(typeof a); 
alert(typeof b);
21
a, 所以 a 是一个局部变量, b 是全局变量
22
[1,2,3].map(function(item,index){
// console.log(item,index);
//parseInt(数值,进制) 
parseInt(1,0); 
parseInt(2,1); 
parseInt(3,2);
});
54. 下面代码输出结果是什么? 
[1,2,3].map(parseInt);
输出结果:[1,NaN,NaN]; 
分析过程:
55. 下面代码执行结果是什么?
执行结果:
报错(Uncaught TypeError: square is not a function)
分析过程:
函数表达式方式声明的函数只提升声明, 不提升赋值, 所以不能再声
明之前调用.
56. 下面代码执行结果是什么?
console.log(square(5)); 
var square=function(n){
return n*n; }
23
for (var i = 1; i <= 5; i++) 
{ (function (i) {
setTimeout(function () 
{ console.log(i);
}, 1000*i)
})(i) }
执行结果: 输出 true
分 析 过 程 : 2.0==2’ 返 回 true; true==new Boolean(true) 返 回 true;
true==1’返回 true; 所以最终结果是 true.
57. 下面的代码会输出什么? 怎么改动下面代码, 使其依次输出
1,2,3,4,5
执行结果:
在控制台输出:6,6,6,6,6 
改造后的代码:
58. 下面代码执行结果是什么?
console.log(2.0=='2'==new Boolean(true)=='1');
for(var 
i=1;i<=5;i++){ setTime
out(function(){
console.log(i);
},1000);
}
var a=10; 
function Foo(){
if(true){
24
// 数组去重
function 
unique(arr){ var 
newArr=[];
for(var 
i=0;i<arr.length;i++){ if(newAr
r.indexOf(arr[i])==-1){
执行结果: 弹出 10
分析过程: let 声明的变量有块级作用域, 所以 let 声明的 a 只在 if 条
件的花括号中生效, 所以会向上级作用域查找.
编码题 
59. 使用 js 封装一个冒泡排序
60. 封装一个方法实现去除数组中的重复元素
方案一:
let a=4; }
alert(a);
}
Foo();
// 冒泡排序
function 
sortBubble(arr){ for(var
i=0;i<arr.length;i++){
for(var j=0;j<arr.length- i;j++){ if(arr[j]>arr[j+1]){
var temp=arr[j]; 
arr[j]=arr[j+1]; 
arr[j+1]=temp; } } }
return arr;
25
alert(arr.join(' '));
方案二:
分析过程:
Set 是es6 中新增的一种数据类型, 和数组很类似, 但是元素不能重复;
Array.from 也是 es6 新增的方法, 可以将类数组对象(伪数组, set), 转
换成数组.
61. 已知数组 var arr=[‘This’, ’is’, ‘Woqu’, ‘Company’], alert 出”This is 
Woqu Company”.
62. 编写一个 js 函数 parseQueryString, 它的用途是把 url 中的参数解
析为一个对象,var url=”http://www.demo.cn/index.html?key1=val1&key2-val2” }
return newArr; }
var arr=[1,2,2,3,3,4] 
Array.from(new Set(arr))
function parseQueryString(argu) 
{ var str = 
argu.split('?')[1]; var result 
= {};
var temp = str.split('&');
for (var i = 0; i < temp.length; i++) 
{ var temp2 = temp[i].split('='); 
result[temp2[0]] = temp2[1];
25
[在此处键入]
63. 统计 str=”jhadfgskjfajhdewqe”字符串中出现最多的字母?
64. 编码实现对象深拷贝
return result; }
function 
countStr(str){ var 
json = {};
// 循环完毕后会得到一个对象,如{a:0,b:1,c:2,d:3,e:4} 
for (var i = 0; i < str.length; i++) {
if (!json[str.charAt(i)]) 
{ json[str.charAt(i)] = 
1;
} else 
{ json[str.charAt(i)]++
; }
};
var iMax = 0; 
var iIndex = '';
// 查找出现次数做多的字符,和出现次数
for (var i in json) 
{ if (json[i] > iMax) 
{
iMax = json[i]; 
iIndex = i; } }
return {
function deepClone(obj) {
if (obj instanceof Obejct) {
let isArray = Array.isArray(obj) 
let cloneObj = isArray ? [] : {} 
for (let key in obj) {
cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key] } }else{
26
65. 有 Student 和 Person 两个类, Person 类有 name 属性和 sayName 方 法, Student 类继承自 Person 类. 分别使用 ES5ES6 的语法实现.
ES6 实现:
ES5 实现
throw new Error('obj 不是一个对象!') }
return cloneObj
}
class 
Person{ constructor(pr
ops){
this.name=props.name; }
sayName(){
console.log(`My name is ${this.name}`);
} }
class Student extends 
Person{ constructor(props) {
super(props); 
this.name=props.name; }
function 
Person(name=''){ this.
name=name; }
Person.prototype.sayName=function(){ cons
ole.log(`My name is ${this.name}`);
}
function 
Student(name){ Person.
call(this,name) }
27
66. 写一个左中右布局占满屏幕, 其中左右两块固定宽度 200,中间自
适应,要求先加载中间块, 请写出结构和样式
Css 样式
html 结构: *{
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>
28
思路分析: html 标签的加载顺序是自上而下, 所以要想让中间部分先
加载, 只需要把中间部分的标签写在最前面即可.
67. 如何扩展 jquery 的静态方法, 如$.getName();
68. 使用 js 求 10000 以内的所有质数的和.
69. 使用 js 打印出 1-10000 之间的所有对称数(121, 1331)
$.extend({
getName: function () {
// do something
}
});
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; }
29
70. 二维数组根据 num 的值进行升序排序:
实现过程:
71. Js 中 eval 的功能是什么? 缺点是什么?
eval 函数的作用: 可以将一个字符串当做 js 代码执行. 
缺点: 执行效率比较低, 不安全.
72. 有一个数列(0,1,1,2,3,5,8,13,21...),定义函数求数列第 n 项
function isSymNum(start, end) {
start = (start <= 11 ? 11 : start); 
for (var i = start; i <= end; i++) {
var strI = +(i.toString().split('').reverse().join('')); 
if (strI == i) {
console.log(i);
} } }
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;
})
30
var init=1;
Object.defineProperty(window, 'a', {
73. 使用什么办法能让如下条件判断成立?
方案一:
方案二:
思路分析:
数组本身有一个 join 方法, 在把数组当做简单数据类型调用的时候, 
会自动调用 join; 而 shift 也是一个数组的方法, shift 是将数组的开头
元素删除, 返回值就是删除的元素, a.join=a.shift 相当于在每一次调用
a 的时候都会调用 shift 方法. 
方案三:
function 
getFibo(n){ if(n==
1) return 0;
if(n==2) return 1;
return getFibo(n-1)+getFibo(n-2);
}
if(a==1&&a==2&&a==3){ conso
le.log('ok') }
var a={
value:1, 
toString:function(){
return this.value++;
} }
var a = [1,2,3]; 
a.join = a.shift;
31
74. 下面代码输出结果是什么? 输出结果: http://www.csser.com/
WebAPI
75.列举 DOM 元素增删改查的 API
创建 DOM: document.createElement(); 
查 找 DOM: 
document.getElementById(); 
document.getElementsByClassName(); 
document.getElementsByName(); 
document.querySelectorAll(); 
document.querySelector();
追加 DOM: parentDom.appendChild();
get: function () 
{ return 
init++;
}
function changeObjectProperty(o){
// 输出的是这个结果
o.siteUrl = "http://www.csser.com/"; 
o = new Object();
o.siteUrl = "http://www.popcg.com/"; }
var CSSer = new Object(); 
changeObjectProperty( CSSer );
console.log( CSSer.siteUrl );
32
移除 DOM: parentDom.removeChild()
76.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: 屏幕有效高度
77.列举几个常见的浏览器兼容问题?
主流浏览器发送 ajax 使用 XMLHttpRequest 创建异步对象,
IE 浏览器时候用 XActive 创建异步对象;
33
主流浏览器注册事件
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
78.什么是事件委托?
本应该注册给子元素的事件, 注册给父元素
79.事件委托的原理是什么?
事件冒泡, 因为有事件冒泡的存在, 所以子元素的事件会向外冒泡, 
触发父元素的相同事件, 根据事件对象可以找到真正触发事件的事
件源.
80.Javscript 中有几种定时器, 有什么区别?
34
setInterval: 间歇定时器, 间隔一定的事件就执行, 执行多次;
setTimeout: 延时定时器, 只执行一次
81.如何实现多个标签页的通信?
localStorage 可以实现同一浏览器多个标签页之间通信的原理;
localStorage 是 Storage 对象的实例。对 Storage 对象进行任何修
改,都会在文档上触发 storage 事件。当通过属性或者 setItem()方
法保存数据,使用 delete 操作符或 removeItem()删除数据,或者调
用 clear()方法时,都会发生该事件。
A.html
B.html
<input type="text"> <button id="btn">Click</button> <script> 
window.οnlοad=function(){
var oBtn=document.getElementById("btn");
var oInput=document.getElementsByTagName("input")[0]; 
oBtn.οnclick=function(){
var val=oInput.value; 
localStorage.setItem("value",val);
} }
</script> <script>
window.addEventListener("storage",function(event){ conso
le.log("value is"+localStorage.getItem("value")); 
console.log("key is"+event.newValue);
},false);
</script>
35
JQuery
82. jquery 中的$.each 和$(selector).each()有什么不同?
$.each 可以循环任何数组, 包括普通数组和 jquery 对象组成的伪数组;
$(selector).each()只能循环遍历 jquery 对象组成的伪数组.
83. Jquery 中$.each 和原生 js 中的 forEach 方法有什么区别?
Jquer 中的$.each 不仅可以循环遍历普通数组, 还可以循环遍历jquery 
对象的伪数组, 原生 js 中的 forEach 只能循环遍历数组; 其次第二个
实参函数的参数顺序不一样, $.each(arr,function(索引,循环单项,数组
本身){}), arr.forEach(function(循环单项,索引,数组本身){})
84. 原生 JS 的 window.onload 与 Jquery 的$(document).ready(function()
{}),$(function () {})有什么不同?
执行时机不一样, window.onload 会等待页面元素渲染完毕并且资源
文件加载完毕后才会执行;$(document).ready(function() {})是当页面元
素渲染完毕后就会执行, 所以执行时机先于 window.onload
85. Jquery 实现连式编程的原理是什么?
jquery 的方法中最后都会 return 一个 this, 这个 this 就是当前元素的
jquery 对象.
function $(parma) {
//如果调用者传入的是一个函数, 则当做入口函数使用
36
86. Jquery 如何多次给同一个标签绑定同一个事件?
使用 addEventListener(‘事件名’,function(){})注册的事件, 不会出现事
件覆盖, jquery 中也是这样做的.
if (typeof (parma) == 'function') 
{ window.onload = parma
} else { //如果调用者传入的是一个选择器, 则返回一个对象
var dom = document.querySelector(parma) 
return { 0: dom,
//{color:'red',border:'1px solid red'} 
css: function (obj) {
if (typeof (obj) == 'object') 
{ for (var key in obj) 
{ dom.style[key] = 
obj[key];
} }
return this;
},
click: function (fn) {
// 注册点击事件
dom.onclick = fn; 
return this;
},
hide: function () 
{ dom.style.display = 
'none'; return this;
},
show: function () 
{ dom.style.display = 
'block'; return this;
},
get: function () 
{ return dom; } } } }
37
87. 如何开发 jquery 插件?
Jquery 提供了两种开发插件的方式:
$.fn: 可以通过任意 jquery 对象来调用
$.extend: 开发的插件只能通过$顶级对象来调用
88. Jquery 中那些方法不支持链式操作?
$.trim(); $.each();$(selector).html(), $(selector).text()
H5 新特性 
89. H5 都新增了那些新特性?
语义化的标签(header,nav,footer,aside,article,section) 
本地存储 sessionStorage,localStorage;
$.fn.green=function(){ console.log(this
,$(this));
$(this).css({background:'green'});
}
// 调用以后, div 的背景色会被设置成 green
$("div").green();
// 定义
$.extend({
alert: function (msg) 
{ alert(msg);
}
});
// 调用
$.alert('这是提示信息')
38
拖拽释放(Drag and drop) API 音频、视频 API(audio,video)
画布(Canvas) API
地理(Geolocation) API
表单控件,calendar、date、time、email、url、search 
新的技术 websocket
90. sessionStorage,localStorage 和 cookie 三者有什么区别?
共同点:它们三者都是浏览器端的存储介质, 可以存储一些数据. 
不同点:
sessionStorage 是将数据存储在页面的内存中, 所以数据会跟随页面
的关闭而销毁, 存储数据相对较少(5M 左右), 只能存储字符串;
localStorage 是将数据存储在电脑的磁盘上, 存储数据量大(20M 左右), 
需要手动删除, 只能存储字符串;
cookie 是http 协议的重要组成部分, 存储数据量相对比较少(4K 左右), 
存储cookie 的时候可以设置过期时间, 到达过期时间后, 会自动销毁, 
如果没有设置, 则跟随浏览器的关闭而销毁. cookie 中存储的数据会
伴随每一次http 请求被发送到服务端, 所以不建议在cookie 中存储大
量数据.
数据交互(ajax)
91. 使用 jquery 写出一个简单的$.ajax 的请求
$.ajax({
39
92. 常见 HTTP 状态码都有哪些?
100 => 正在初始化(一般是看不到的)
101 => 正在切换协议(websocket 浏览器提供的)
200 或者以 2 开头的两位数 => 都是代表响应主体的内容已经成功返
回了
202 => 表示接受
301 => 永久重定向/永久转移
302 => 临时重定向/临时转移(一般用来做服务器负载均衡)
304 => 本次获取的内容是读取缓存中的数据,会每次去服务器校验
400 => 参数出现错误(客户端传递给服务器端的参数出现错误)
401 => 未认证,没有登录网站
403 => 禁止访问,没有权限
404 => 客户端访问的地址不存在
500 => 未知的服务器错误
503 => 服务器超负荷(假设一台服务器只能承受 10000 人,当第
10001 人访问的时候,如果服务器没有做负载均衡,那么这个人的网
络状态码就是 503)
url:'/api',
type:'post',
data:{}, 
dataType:'json', 
success:function(res){
console.log(res);
}
});
40
93. 你知道的 HTTP 请求方式有几种?
1. GET 请求指定的页面信息,并返回实体主体。
2. HEAD 类似于 get 请求,只不过返回的响应中没有具体的内容,
用于获取报头
3. POST 向指定资源提交数据进行处理请求(例如提交表单或者
上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资
源的建立和/或已有资源的修改。
4. PUT 从客户端向服务器传送的数据取代指定的文档的内容。
5. DELETE 请求服务器删除指定的页面。
6. CONNECT HTTP/1.1 协议中预留给能够将连接改为管道方式的代
理服务器。
7. OPTIONS 允许客户端查看服务器的性能。
8. TRACE 回显服务器收到的请求,主要用于测试或诊断。
9. PATCH 实体中包含一个表,表中说明与该 URI 所表示的原内容
的区别。
10. MOVE 请求服务器将指定的页面移至另一个网络地址。
11. COPY 请求服务器将指定的页面拷贝至另一个网络地址。
12. LINK 请求服务器建立链接关系。
13. UNLINK 断开链接关系。
14. WRAPPED 允许客户端发送经过封装的请求。
15. LOCK 允许用户锁定资源,比如可以再编辑某个资源时将其锁
41
定,以防别人同时对其进行编辑。
16. MKCOL 允许用户创建资源
17. Extension-mothed 在不改动协议的前提下,可增加另外的方
法。
94. 请尽可能详尽的解释 ajax 的工作原理
第一步:创建一部对象 var xhr=new XMLHttpRequest() 
第二步:设置请求行 xhr.open(‘请求方式’,请求地址); 
第三步:发送请求 Get 方式 xhr.send(null),
如果是 post 请求还要设置请求头
95. 页面编码和被请求的资源编码如果不一致如何处理?
a.html 的编码是 gbk 或 gb2312 的。 而引入的 js 编码为 utf-8 的 ,
那就需要在引入的时候
<script src="http://www.xxx.com/test.js" charset="utf-8"></script>
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) } }
42
同理,如果你的页面是 utf-8 的,引入的 js 是 gbk 的,那么就需要加
上 charset="gbk".
96. 如何解决跨域问题?
jsonp, 服务器代理, cors
97. jsonp 跨域的原理是什么?
动态在页面中创建一个 script 标签, 使其 src 属性指向后端数据接口, 
后 端 数 据 接 口 必 须 返 回 一 个 js 函 数 的 调 用 字 符  (cb({“name”:”zs”,”age”:18})), 将要返回给前端的 json 数据作为函数的
实参, 当 script 标签加载完毕后会在浏览器中执行后端返回的函数调
用,所以前端必须事先对调用的函数进行声明. 因为函数是在 js 中声
明的, 所以可以在函数内部拿到服务端调用的时候传入的实参, 所以
就间接实现了跨域请求数据.
98. 什么是同步和异步, 那种执行方式更好?
同步是指一个程序执行完了接着去执行另外一个程序, 异步是指多个
程序同时执行. 所以异步效率更高, 因为异步不会出现阻塞现象, 前一
个程序的执行不会影响后一个程序的执行.
99. GETPOST 的区别,何时使用 POSTget 是将要传递的参数拼在 url 中进行传递,传递数据量少, 不安全
43
post 是将传递的参数放在请求体里传递, 携带数据量大, 相对安全. 
要提交一些敏感数据(比如登录密码),上传文件时, 必须使用 post 
请求.
100. 请解释一下 JavaScript 的同源策略
同源策略是浏览器的一项安全策略, 浏览器只允许 js 代码请求和当
前所在服务器域名,端口,协议相同的数据接口上的数据,这就是同源策 略.
101. 一个页面从输入 URL 到页面加载显示完成,这个过程中都发
生了什么?
首先根据域名查询 DNS 服务器获取服务器 IP,然后拿着服务器 IP 和
域名请求对应的服务器, 请求成功后 web 服务器会根据一系列运算, 将
客户端需要的数据通过网络传输到客户端浏览器, 最终由浏览器解
析后呈现给终端用户.
102. 网站从 http 协议切换到 https 协议需要对代码做哪些处理? 
不需要对代码做任何处理, 只需要在 web 服务器中加入一个 ssl 的安
全认证模块即可.
103. 什么是 RESTful API?
RESTful 的核心思想就是使用 HTTP 请求方式配合资源对象的方式来
44
完成对服务端某个资源的操作(HTTP 动词+资源对象)。
比如,GET /articles 这个命令,GETHTTP 动词,/articles 是资源对
象。
补充说明:
动词通常就是五种 HTTP 方法,对应 CRUD 操作:
GET:读取(Read)
POST:新建(Create)
PUT:更新(Update)
PATCH:更新(Update),通常是部分更新
DELETE:删除(Delete)
性能优化 
104. 什么是渐进增强和优雅降级?
渐进增强(progressive enhancement):针对低版本浏览器进行构建
页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等
改进和追加功能达到更好的用户体验。(从被所有浏览器支持的基本
功能开始,逐步地添加那些只有新式浏览器才支持的功能,向页面添
加无害于基础浏览器的额外样式和功能。当浏览器支持时,它们会自
动地呈现出来并发挥作用。)
优雅降级(graceful degradation):一开始就构建完整的功能,然后
再针对低版本浏览器进行兼容。(Web 站点在所有新式浏览器中都能
45
正常工作,如果用户使用的是老式浏览器,则代码会检查以确认它们
是否能正常工作。由于 IE 独特的盒模型布局问题,针对不同版本的
IE 的 hack 实践过优雅降级了,为那些无法支持功能的浏览器增加候
选方案,使之在旧式浏览器上以某种形式降级体验却不至于完全失
效。)
区别:优雅降级是从复杂的现状开始,并试图减少用户体验的供给,
而渐进增强则是从一个非常基础的、能够起作用的版本开始,并不断
扩充,以适应未来环境的需要。
105. 什么是页面的回流和重绘?
回流是指当页面的结构或者标签的尺寸发生变化的时候, 浏览器需
要对页面进行重排, 并重新渲染;
重绘是指当页面上的标签的外观(比如字体颜色,或背景颜色)发生改
变的时候, 浏览器需要重新对页面进行渲染.
所以回流一定会引起页面的重绘, 重绘不一定会引起回流. 
要提高页面性能, 就要尽可能的减少页面的回流和重绘.
106. 针对页面性能优化,你有哪些优化方案? 
资源加载方面:
减少 http 请求次数, 具体方案, 代码合并(合并 css,js), 使用精灵图; 
减少 http 请求数据量, 代码压缩(css,js,html), 合理设置缓存;
46
启用 CDN 加速服务; 
代码层面:
避免滥用全局变量, 减少作用域查找(能用局部变量就不要声明全局
变量), 不要滥用闭包;
减少 DOM 操作, 操作 DOM 的时候对已经查找到的 DOM 对象进行缓
存, 避免重复查找;
使用图片懒加载, 避免单次加载图片数量过多导致页面卡顿; 将
script 标签写在页面底部, 因为 js 的加载会阻塞页面的渲染;
不要在本地书写大量 cookie, 因为 cookie 会伴随每一次 http 请求;
107. 什么是 CDN 加速?
CDN(Content Delivery Network)全称内容分发网络, 是运营商所提供
的一项增值服务, 花钱就可以拥有这项加速服务. CDN 主要是对网站
的静态资源进行加速, CDN 在全国会有很多节点服务器(每个城市都
有), 当你购买了一个 CDN 服务以后, CDN 服务器会对你的网站的静态
资源文件进行缓存处理, 当第二次有人访问的时候, 那么服务器就会
从就近的 CDN 节点服务器上获取网站所需的静态资源, 由于 CDN 服
务器的性能比较高, 并且距离客户端的物理距离比较近, 所以就可以
实现加速. 启用 CDN 服务只需要在运营提供商提供的后台进行配置
(配置要对那个域名启用 CDN 服务), 不需要对代码做任何修改.
108. 什么是 SEO?
47
SEO(Search Engine Optimizing)搜索引擎优化, 就是让搜索引擎去抓取
我们的网页. 为了让搜索引擎抓取我们的网页, 我们可以在书写代码
的时候做一些工作, 比如合理设置网页 title(标题), keywords(关键
字),description(描述); 因为搜索引擎在抓取到网页以后首先回去分析
这几个关键信息.
109. 为什么利用多个域名来存储网站静态资源会更有效?
因为浏览器对请求静态资源文件有一个并发数量限制, 每次只能请求
同一个域名下的若干个资源文件(根据浏览器的不同会有差异), 如果
把资源文件存放在多个不同的域名下面就会突破浏览器的限制;
其次, 启用多个静态资源服务器,可以减轻主服务器的压力.
110. 移动端点击事件会有多少秒的延时?什么原因造成的?如何解
决?
移动端的点击事件会有 300ms 的延时;
是因为浏览器为了保留双击缩放的功能所造成的,早期浏览器都有一
个双击缩放的功能, 在用户点击一次以后, 浏览器会等待第二次点击, 
如果用户在 300ms 内进行了第二次点击, 那么浏览器就会执行缩放的
功能, 如果 300ms 内没有再次点击, 则会当做单击事件处理;
解决方案:
使用touch 触摸事件来模拟点击事件;使用fastclick 插件来解决;静止页
面缩放功能
48
111. 你了解到的网站攻击方式有哪些?
常见的网站攻击方式有 xss(跨站脚本攻击), csrf(跨站请求伪造)
112. 谈谈 js 中的垃圾回收机制
主要有以下两种方式:
(1)标记清除(mark and sweep):
大部分浏览器以此方式进行垃圾回收,当变量进入执行环境(函数中
声明变量)的时候,垃圾回收器将其标记为“进入环境”,当变量离
开环境的时候(函数执行结束)将其标记为“离开环境”,在离开环
境之后还有的变量则是需要被删除的变量。标记方式不定,可以是某
个特殊位的反转或维护一个列表等.垃圾收集器给内存中的所有变量
都加上标记,然后去掉环境中的变量以及被环境中的变量引用的变量的
标记。在此之后再被加上的标记的变量即为需要回收的变量,因为环
境中的变量已经无法访问到这些变量。
(2)引用计数(reference counting):
这种方式常常会引起内存泄漏,低版本的 IE 使用这种方式。机制就
是跟踪一个值的引用次数,当声明一个变量并将一个引用类型赋值给
该变量时该值引用次数加 1,当这个变量指向其他一个时该值的引用
次数便减一。当该值引用次数为 0 时就会被回收。
113. Js 是单线程还是多线程?
49
单线程, 单位时间内只能处理一个进程
114. Js 是如何实现异步操作的?
Js 虽然是单线程的, 但是浏览器是多线程的, js 中的异步操作基本都
是由浏览器提供的子线程来完成的.
115. 分别介绍下 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(view
model)视图模型层, 负责连接数据层和视图层, 将数据层的数据交给
视图层展示, 将视图层的行为传递给数据层.
MVP 也是从后端的 MVC 设置模式中演化过来的, 主要应用于安卓开
发中. M(model) 数据层, V(view) UI 逻辑; P(Presenter)业务逻辑
ES6/7/8 新特性 
116. Es6 中新增了那些数据类型?
50
Symbol 类型(基本)
Set 类型(复杂)
Map 类型(复杂)
WeakSet 类型(复杂)
WeakMap 类型(复杂)
TypedArray 类型(复杂)
117. ES6 新增了那些特性?
const(声明常量), let(声明变量)关键字;
map 和 set 数据类型; 
模板字符串;
对象数组解构赋值; 
函数剩余参数;(...arg)
延展运算符;(...)
函数默认参数;fn(name=’zs’)
对象字面量的增强(属性名和属性值相同, 可缺省);
Promise 异步对象;
class 类的支持
118. 使用 let 声明的变量和 var 声明的变量有什么区别?
使用 let 声明的变量有块级作用域, 并且没有变量的声明提升( 使用
let 声明的变量在声明之前调用会报语法错误); 使用 var 声明的变量
51
class 
Person{ constructor(pr
ops){
this.name=props.name; 
this.age=props.age; } }
// Student 继承 Person
class Student extends Person{
有声明提升(在声明之前调用会报 undefined), 没有块级作用域.
119. 谈谈 async/await 的使用方式和场景
async 是用来修饰函数的声明, 使用async 修饰的函数会变成一个异步
函数. await 用来修饰函数的调用,await 修饰的函数必须返回一个
promise 异步对象, 使用 await 修饰后, 就会将 promise 异步对象转换
成一个同步操作.
120. 箭头函数有什么作用及实际应用场景?
箭头函数可以使函数内部的 this 指向和函数外部保持一致; 箭头函数
之所以可以让函数内部的 this 指向和外部保持一致是因为箭头函数
内部没有 this 指向. 可以在 ajax 的回调函数中使用箭头函数让回调函
数中的 this 指向事件源; 可以在定时器的第二个参数中使用箭头函数, 
避免函数内部的 this 指向全局 window.
121. class 类的如何实现继承
使用 extends 关键字实现继承
52
122. 谈谈对 Promise 的理解
Promise 本身并没有提供任何的代码逻辑, 它可以帮助我们改造或优
化传统的使用回调函数实现的异步操作, 让我们以一种更优雅的方式
来实现异步操作. 最显著的一个特点就是通过 Promise 可以解决传统
的回调地狱. 代码层面 Promise 提供了一个构造函数, 在使用的时候
必须通过 new 创建一个实例对象, 在创建实对象的时候需要传递一
个匿名函数, 这个匿名函数需要两个参数(resolve,reject), resolve 成功
处理函数, reject 失败处理函数. 什么时候触发成功处理函数和失败处
理函数, 由具体的业务逻辑来决定. resolve 和 reject 需要通过
Promise 实例对象提供的 then 方法来传递.Promise 提供了两个静态方
法 all,race,all 可以一次执行多个 Promise 实例, 返回值是数组; race 也
可以一次执行多个 Promise 实例, 哪个实例最先执行完, 就返回哪个
的执行结果.
前端框架 
Vue
123. vue 中如何封装一个组件
首先定义一个后缀名为.vue 的文件. 文件内部还是三部分组成,
super(props); 
this.score=props.score; } }
53
template 模板部分, script 逻辑部分, style 样式部分. 这三部分是组件
的核心部分, 组件需要哪些结构, 在模板部分书写, 需要什么样的外
观样式, 通过 style 部分书写, 有哪些行为在 script 部分书写.一定要在
script 部分使用 es6 模块化的导出语法(export default{}), 进行导出. 然
后在需要调用组件的地方使用 es6 模块化导入语法导入即可, 组件需
要哪些参数, 直接在调用的部分进行传递即可.主要逻辑还是在组件中
完成.
124. Vue 中 computed 和 watch 的区别?
computed 是计算属性, 可以根据 data 中的数据成员,动态计算出一个
新的数据成员(这个数据成员在 data 中并不存在), 计算属性的函数必
须有返回值; watch 是监视器, 可以监视 data 中某一个数据成员的改
变或路由中的某些属性的改变, 可以根据这个改变, 做一些其他操作
(不仅仅局限于更新其他相关数据).
Watch 监听器:
var vm = new 
Vue({ el: 
'#demo', data: 
{
firstName: 'Foo', 
lastName: 'Bar', 
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
54
计算属性:
125. 谈谈对 vue 中插槽的理解?
Vue 中的插槽分为三种, 匿名插槽, 具名插槽, 作用域插槽.
通过插槽可以动态指定某一个组件模板部分的渲染, 我们在调用组件
的时候, 在组件的调用标签中间传递了什么样的标签结构, 那么该组
件就会把我们传递的标签结构放在他的模板部分进行渲染.
126. v-show 和 v-if 在隐藏一个元素的时候有什么不同, 应该如何
来选择? v-show 是通过 css 的方式来隐藏元素, 而 v-if 是根据条件是否成立决
定是否要创建元素. 如果某个元素需要频繁切换显示状态的话, 建议
是使用 v-show, 因为频繁创建销毁 DOM 需要性能开销.
127. 什么是 Vuex, 在那种场景下使用? }
})
var vm = new 
Vue({ el: 
'#demo', data: 
{
firstName: 'Foo', 
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
} }
55
Vuex 是针对 vue 的一个状态管理工具. 有几个核心的部分:
state 存储状态数据;
mutations: 更新数据的方法,
actions: 调用 mutations 中的方法, 更新 state 数据;
getters: 对 state 中的数据进行预处理
当组件的关系比较复杂的时候, 可以使用 vuex 简化组件间的传值.
128. 说说 Vue 路由的使用步骤? 
第一步:下载路由模块 vue-router; 
第二步:创建路由对象;
第三步:配置路由规则;
第四步:将路由对象注册为 vue 实例对象的成员属性
129. 你所了解到的常见 Vue 组件库有哪些?
PC 端组件库: element-ui, ant-design, iview
移动端: mint-ui, vant, vux
130. 谈谈对于 MVVM 的理解?
MVVM 由三部分组成M(model 数据层), V(view 视图层),VM(view-model) 
视图模型层. 是一种框架的设计思想, vue 就是基于 mvvm 来设计的. 其 中 M(model) 层 是 负 责 初 始 化 数 据 ,V(view) 只 负 责 页 面 展 示,VM(view-model)用来连接 view 层和 model 层, 将数据层的数据传
56
递一个视图层进行展示, 将视图层的操作传递到数据层进行持久化.
131. Vue 的生命周期? 
创建阶段: 只执行一次
beforeCreate(开始进行一些数据和方法的初始化的操作, data 中的数
据和 methods 中的方法还不能用),
created(已经完成数据和方法的初始化, data 中的数据和 methods 中
的方法可以使用了),
beforeMount(开始渲染虚拟 DOM),
mounted(已经完成了虚拟 DOM 的渲染, 可以操作 DOM, 只执行一
次)
运行阶段: 执行多次
beforeUpdate(data 中的数据即将被更新, 会执行多次)
updated(data 中的数据已经更新完毕, 会执行多次) 
销毁阶段: 只执行一次
beforeDestroy(vue 实例即将销毁, 此时 data 中的数据和 methods 中的
方法依然处于可用状态)
destroyed(vue 实例已经销毁, 此时 data 中的数据和 methods 中的方
法已经不可用)
132. Vue 实现数据双向绑定的原理?
Vue 是使用数据劫持, 结合发布者订阅者模式实现双向数据绑定的
57
执行过程分析:
读取 title 或者 msg 的时候 get 方法会自动触发; 重新给 title 或 msg
赋值的时候,set 方法会被自动触发(可以在此处通知界面层更新)
133. Vue 创建组件的时候,data 为什么要使用匿名函数 return 一个
// 初始值
var data = 
{ msg: 
'hello', 
title: '标题' }
for (var key in data) 
{ Object.defineProperty(window, key, 
{
get: function () {
// console.log('get 被触发了'); 
return data[key];
},
set: function (input) {
// do something: 如通知界面层更新
console.log(input, '假装在通知界面');
}
});
}
title = 'title 初始值'; 
console.log(title);
58
// 父组件
Vue.component('parent',{ t
emplate:`
<div>
<child :msgFromParent="msg"></child>
<div>`, 
data:function(){
return {
title:'父组件的标题',
msg:'这是传给子组件的值' }
},
// 子组件
components:{
child:{
// 模板
template:`
对象?
因为对象是一种引用数据类型,在内存中只有一份. 如果 data 的值直
接是一个对象的话, 那么后期组件在不同的地方多次调用的时候, 会
相互产生影响, 因为每一次调用操作的 data 对象是一样的. 使用函数
的方式返回对象, 可以保证组件的每一次调用都会创建一个新对象, 
这样组件的每一次调用不会相互产生影响.
134. Vue 中实现父组件向子组件传递数据?
第一步: 在子组件的调用标签上声明一个自定义属性, 属性值来自父
组件的 data
第二步: 在子组件的定义部分声明一个属性 props, 值是一个数组, 将
自定义属性的名字在 props 中进行声明; 在子组件的模板部分可以使
用 props 中声明过的数据.
59
135. Vue 中如何实现子组件向父组件传递数据?
第一步: 在子组件的调用标签只上通过 v-on 动态绑定一个自定义事
件, 自定义事件的处理函数必须在父组件的 methods 中提前声明, 这
个函数需要一个形参, 来接收子组件传递过来的数据.
第二步: 在子组件中通过 this.$emit(自定义事件,数据)触发自定义事
件的执行, 此动作可以放在子组件的 created/mounted 生命周期中, 
可以放在某个事件处理函数中.
136. Vue 中实现兄弟组件间的传递数据?
第一步: 声明一个空的 Vue 实例对象 comm, 作为事件中心的角色第
二步: 在 acom 组件中通过 comm.$emit(自定义事件,数据)的方式触发
事件(此操作可放在某个事件处理函数或者 acom 组件的生命周期函
数 created/mounted 中)
第三步: 在 bcom 组件中通过 comm.$on(自定义事件,function(data){})
<div>
<h1>{{msgFromParent}}</h1>
</div>`,
// 数据模型
data:function(){ 
return {
title:'子组件标题' }
},
//获取父组件中传过来的值
props:['msgFromParent'] } }
});
60
监听自定义事件的执行( 操作可放在 bcom 组件的声明周期函数
created/mounted 中)
// 公共组件
var comm=new Vue();
// 兄弟组件 1
Vue.component('coma',{ te
mplate:`
<div>
<h1>{{title}}</h1>
<button @click="sendMsg">发送</button>
</div>
`, 
data:function(){
return {
title:'组件 A',
msg:'传给兄弟组件的值' }
},
methods:{
sendMsg:function(){ comm.$emit('myev
ent',this.msg) }
},
created:function(){
// 注册自定义事件
comm.$emit('myevent',this.msg);
console.log('注册事件 OK');
}
});
// 兄 弟 组 件 2 
Vue.component('comb',{
template:`
<div>
<h1>{{title}}</h1>
<h1>{{msg}}</h1>
</div>
`, 
data:function(){
return {
61
137. Vue 中有几种路由模式? Vue
中的路由模式有两种:hash,history; 默认是hash模式; 可以在创建路
由对象的时候, 使用 mode 属性来切换路由模式.
const router=new Router({mode:’history’})
138. Vue 路由导航守卫是什么, 以及应用场景
路由守卫是在页面进行路由跳转的时候做一些处理, 比如拦截. 
vue-router 中提供了下面几种路由导航守卫:
全局前置守卫
全局后置钩子
title:'组件 B',
msg:''
}
},
mounted:function(){ comm.$on('myeven
t',(data)=>{
this.msg=data 
console.log(data);
});
}
});
const router = new VueRouter({ ... }) 
router.beforeEach((to, from, next) => {
// from 从里来
// to 到哪里去
// next 是否要放行
})
62
路由独享守卫: 在声明路由的时候, 针对特定路由的钩子函数
139. Vue 如何自定义一个过滤器?
定义全局过滤器:
Vue.filter(‘过虑器名称’,function(input){ return input });
定义局部过滤器:
140. Vue 如何自定义一个 vue 指令?
定义全局指令:
router.afterEach((to, from) => {
// ...
})
const router = new 
VueRouter({ routes: [ {
path: '/foo', 
component: Foo,
beforeEnter: (to, from, next) => {
// ...
} } ]
})
new Vue({
filters:{ dateFmt:function(inpu
t){ return 'yyyy-mm-dd'; } }
})
63
const router=new 
VueRouter({ routes:[ {path:'/product/:id',component:Product} ]
});
// 获 取 参 数 : 
this.$route.params.id
Vue.directive(‘指令名’,function(el,binding){});
定义私有指令:
141. 怎么定义 vue-router 的动态路由? 怎么获取通过路由传过来
的参数?
142. Vue 路由模块中$route 和$router 的区别?
$route 中存储的是跟路由相关的属性(如$route.params,$route.query) ;
$router 中存储的是和路由相关的方法(如$router.push(),$router.go()),
143. vue 中 v-for 指令循环遍历中 key 属性的作用?
Key 属性的作用是在数据层和视图层之间建立一一对应关系, 方便后
期对页面进行局部更新. 如果某一条数据发生改变, 只更新当前数据
对应的 DOM 元素.
new Vue({
directives:{ focus:function(el,bindin
g){
} }
});
64
144. Vue 和 react 有哪些不同的地方?
Vue 实现了双向数据绑定(数据<=>界面);react 仅仅实现了单项数据流
(数据层=>界面层); vue 中提供了指令, react 中没有指令的概念. vue 中
使用插值表达式在进行数据渲染, react 中使用 jsx 进行数据的渲染.
145. Vue 有哪些常用的事件修饰符?
.prevent: 阻止默认事件;
.stop: 阻止冒泡;
.once: 事件执行一次;
.self: 只当在 event.target 是当前元素自身时触发处理函数
146. 列举 Vue 中常用的指令
v-model:实现双向数据绑定; 
v-bind: 绑定属性; v-on:注册事件; v-html: 设置标签内容(允许内容 html)
v-text: 设置标签的内容(不允许包含 html) 
v-clack: 解决插值表达式闪烁问题
V-for: 循环遍历数组或对象
147. Vue 中如何解决插值表达式闪烁问题? 
使用 v-html 或 v-text 替代插值表达式;
65
window.addEventListener('hashchange',function(){ conso
le.log('hash change');
});
使用 v-clack 解决插值表达式闪烁,
第一步:声明属性选择器[v-clack]{display:none} 
第二步:在插值表达式所在标签添加属性 v-clack
148. Vue 路由中如何实现通过锚点值的改变切换组件? 
通过监听 hashchange 事件, 具体如下:
149. vue 中如何实现给样式添加作用域?说明其实现原理
vue 中要给样式添加作用域, 只需要给 style 标签添加 scoped 属性即
可.
实现原理:
添加了scoped 属性的style 标签内的样式会被改写成一个交集选择器, 
会在原来类名的基础上添加一个随机属性(.container[v-abcde]), 同 时 引 用 该 类 名 的 标 签 也 会 添 加 一 个 相 同 的 属  (<div 
class=”container” v-abcde></div>) , 这样的话, 这个类名就可以对引
用它的标签生效, 同时不会影响其他同类名的标签.
150. Vue 中如何动态添加一个路由规则? 
使用 router.addRoutes([{path:’’,component:’’}])
66
151. Vue 中有何优化页面的加载效率? 
使用路由懒加载和组件懒加载;
不要打包一些公共的依赖(vue, 组件库); 
使用 CDN 加载这些依赖文件
152. 什么是路由懒加载? 路由懒加载有什么好处? 如何实现路由
懒加载?
路由懒加载是指通过异步的方式来加载对应的路由组件(默认情况是
将所有的组件全部加载并打包).
路由懒加载的好处: 可以提高页面的加载速度, 尤其是首页的加载速
(因为使用了懒加载后, 加载首页的时候, 就不需要加载其他页面对
应的组件, 在需要的时候再加载)
具体实现:
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)
67
153. Vue 中如何触发一个自定义事件?
通过 this.$emit(event, ’数据’) 可以触发自定义事件的执行.
154. Vue 中如何监听自定义事件的执行?
通过 this.$on(event,callback)可以监听自定义事件的执行
155. Vue 中如何移除自定义事件?
通过this.$off(event,callback)可以移除一个自定义事件; 如果某些特殊
场 景 下 , 一个事件被触发一次后就需要将其移除, 可 以 使 用
this.$once(event,callback)进行事件注册
156. vm.$mount(selector)方法的作用是什么?
手动将一个 vue 实例挂载到页面上
157. Vue 中 keep-alive 组件的作用是什么?
mode:'history'
});
var MyComponent = 
Vue.extend({ template: 
'<div>Hello!</div>'
})
// 创建并挂载到 #app (会替换 #app) 
new MyComponent().$mount('#app')
// 同上
new MyComponent({ el: '#app' })
68
keep-alive 可以将被包裹的组件暂存在内存当中, 当页面切换的时候, 
组件不会被重复的销毁和创建, 从而可以提高整体性能, 同时也可以
保存组件的一些状态.
158. Vue 中如何手动销毁一个 vue 实例?
调用 vm.$destroy()可销毁一个 vue 实例(清理它与其它实例的连接,
解绑它的全部指令及事件监听器)
159. Vue 中有哪些内置的组件?
component, slot, transition, transition-group, keep-alive
160. vue 实例中有哪些属性?
vm.$data 可以获取 vm 实例对象 data 中的数据;
vm.$props 可以获取 vm 组件接收到的 props 对象数据;
vm.$el 可以获取 vm 实例对象的根 dom 元素;
<!-- 动态组件由 vm 实例的属性值 `componentId` 控制 --> <component :is="componentId"></component>
<!--tansition 动画组件的使用--> <transition> <div v-if="ok">toggled content</div>
</transition>
var MyComponent = 
Vue.extend({ template: 
'<div>Hello!</div>'
})
69
vm.$refs 可以获取 vm 实例中注册过 ref 特性的所有 dom 元素和组件
实例.
161. Vue.use(plugin)的作用是什么, 使用的时候需要注意什么问题?
Vue.use 的作用是安装一个 Vue 插件, 该方法需要在调用 new Vue()
之前被调用.
162. vm.$nextTick(fn)的作用是什么?
延迟某个操作的执行, 直到 dom 更新以后在执行.
163. vue 中的混入(mixin)有什么作用?
var vm = new MyComponent().$mount() 
document.getElementById('app').appendChild(vm.$el) <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 = '这是更新以后的标题';
});
}
});
70
混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可
复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对
象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行
“合并”。比如,数据对象在内部会进行递归合并,并在发生冲突时以
组件数据优先。同名钩子函数将合并为一个数组,因此都将被调用。
另外,混入对象的钩子将在组件自身钩子之前调用。
164. 如何开发一个 vue 插件?
Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是
Vue 构造器,第二个参数是一个可选的选项对象
// 定义插件
const 
myPlugin={ install:(Vue,option
s)=>{
// 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 () {
71
165. 什么是 ssr? 如何实现 ssr?
ssr 是全拼(server side rendering) ,中文意思, 服务端渲染, 让页面的渲
染在服务端完成, 生产环境必须部署nodeJS 的环境, 因为服务端渲染
必须借助 nodeJS 来完成. vue 中可以使用 nuxt 框架实现服务端渲染.
166. 什么是 SPA?
SPA(Single Page Application), 单页面应用程序, 使用vue, react, angular 
创建的项目都属于 SPA. 因为整个项目只有一个页面, 其他页面都是
在该页面的基础上局部刷新而来的.
传统方式创建的项目都是 MPA(Mutilple Page Application)多页面应用
程序.
167. 使用 vue,react,angular 开发的 SPA 单页面应用有什么优缺点? }
})
// 5. 注册全局组件
Vue.component('myCompent',{ templa
te:'<h1>loading...</h1>'
});
} }
export default myPlugin;
// 调用插件
Vue.use(myPlugin,{})
72
单页面应用虽然性能方面得到了提升, 但是有一个致命的缺点就是不
利于 seo, 搜索引擎几乎不会抓取单页面应用.
168. 某某公司 vue 机试题
Html 部分
<div id="app"> <div> <input type="text" v-model="phone1"> <button @click="getHandle">get 测试</button> <span>{{res1}}</span>
</div> <div> <input type="text" v-model="phone2"> <button @click="postHandle">post 测试</button> <span>{{res2}}</span>
</div>
</div>
73
Js 部分
React
169. 什么是虚拟 DOM, 使用虚拟 DOM 有什么优势?
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom 
diff 算法避免了没有必要的 dom 操作,从而提高性能。
用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个
真正的 DOM 树,插到文档当中,当状态变更的时候,重新构造一棵
新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把所
new 
Vue({ el: 
'#app', 
data: {
phone1: 123,
phone2: 456, 
res1:'',
res2:'', 
baseUrl:'http://47.96.26.207:8099/api/Users'
},
methods: 
{ getHandle() 
{
axios.get(`${this.baseUrl}/GetTest?phone=${this.phone1}`,).then 
((data)=>{
this.res1=data.result;
});
},
postHandle() 
{ axios.post(`${this.baseUrl}/PostTest`,{phone:this.phone2}).then
(({data})=>{
this.res2=data.result;
});
} }
74
记录的差异应用到步骤 1 所构建的真正的 DOM 树上,视图就更新
了。
170. 简单介绍下 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) }
})
75
171. 什么是 Redux?
Redux 是一个状态管理工具, 不仅可以在 react 中使用, 也可在其他框
架中使用, 甚至可以脱离框架本身使用. redux 中有几个核心的组成部
分:
store 存储数据的对象,必须通过 createStore 方法来创建;
action 更新数据的规则, 必须有一个属性 state, 值必须是字符串;
reducer 更新数据的函数, 需要传入 state 状态数据和 action 更新规则. 
在 react 中使用 redux 的时候, 一般会使用 react-redux 来简化使用步
骤.
172. React 有哪些常用的组件库?
PC 端组件库:
element-ui(饿了么推出的前端组件库), ant-design(阿里巴巴的前端组
件库, 几乎覆盖了三大框架); zent(有赞推出的 PC 端组件库)
173. React 中如何操作 DOM?
}
// 节点替换函数
function repleaseNode(vnode, newVnode) 
{ var elem = vnode.elem
var newEle = createElement(newVnode) }
76
在需要进行 dom 操作的标签上设置一个 ref 属性, 保证值不要重复, 
后期在js 部分可以通过”this.refs.属性名”来获取标签的虚拟dom 对象.
174. 什么是高阶组件(HOC)?
函数的返回值是一个函数, 我们称之为高阶函数. 同理一个组件返回
值如果还是一个组件, 那么就称之为高阶组件. redux 中提供的
connect 就是一个高阶组件.
175. React 中调用 setState 后发生了什么?
在代码中调用 setState 函数之后,React 会将传入的参数对象与组件
当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过
调和过程,React 会以相对高效的方式根据新的状态构建 React 元素
树并且着手重新渲染整个 UI 界面。在 React 得到元素树之后,React 
会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最
小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位
置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部
重新渲染。
176. React 中状态 state 和属性 props 有什么不同?
state 是组件的私有数据, 可读可写, props 是只读属性, 一般来自外部
(比如父组件)
77
177. React 中有几种创建组件的方式?
通过函数的方式创建组件, 此种方式创建的组件为无状态组件(不常
用);
React.createClass();
通过 class 类的方式创建组件(须继承 React.Component), 实际开发中
使用此种方式.
178. React 中的组件按照职责不同, 可以分为几种类型? 
根据组件的职责通常把组件分为 UI 组件和容器组件;
UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑; 
两者通过 React-Redux 提供 connect 方法联系起来.
179. 类组件(Class component)和函数式组件(Functional component)
之间有何不同?
类组件不仅允许你使用更多额外的功能,如组件自身的状态和生命周
期钩子,也能使组件直接访问 store 并维持状态;当组件仅是接收
props,并将组件自身渲染到页面时,该组件就是一个 '无状态组件
(stateless component)',可以使用一个纯函数来创建这样的组件。这
种组件也被称为哑组件(dumb components)或展示组件.
180. 说说 react 的生命周期函数? 
初始化阶段:
78
getDefaultProps:获取实例的默认属性
getInitialState:获取每个实例的初始化状态
componentWillMount:组件即将被装载、渲染到页面上
render:组件在这里生成虚拟的 DOM 节点
componentDidMount:组件真正在被装载之后
运行中状态:
componentWillReceiveProps:组件将要接收到属性的时候调用
shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以
返回 false,接收数据后不更新,阻止 render 调用,后面的函数不会
被继续执行了)
componentWillUpdate:组件即将更新不能修改属性和状态
render:组件重新描绘
componentDidUpdate:组件已经更新
销毁阶段:
componentWillUnmount:组件即将销毁
181. react 性能优化可以使用哪个生命周期函数?
shouldComponentUpdate 这个方法用来判断是否需要调用 render 方
法重新描绘 dom。因为 dom 的描绘非常消耗性能,如果我们能在
shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,
可以极大的提高性能。
79
182. 应该在 React 组件的何处发起 Ajax 请求? 在 React 组件中,应该在 componentDidMount 中发起网络请求。这
个方法会在组件第一次“挂载”(被添加到 DOM)时执行,在组件的生命
周期中仅会执行一次。更重要的是,你不能保证在组件挂载之前 Ajax 
请求已经完成,如果是这样,也就意味着你将尝试在一个未挂载的组件
上调用 setState,这将不起作用。在 componentDidMount 中发起网
络请求将保证这有一个组件可以更新了。
183. React 如何实现服务端渲染?
Next.js 是一个轻量级的 React 服务端渲染应用框架.
184. 自定义的 react 组件首字母为什必须要大写?
Babel 在对 jsx 代码进行编译的时候, 如果首字母大写, 就把其当做
react 组件编译, 编译成 js 对象; 如果首字母小写,则认为是一个普通
的 html 标签, 会解析成普通字符串.
185. setState 什么时候是同步,什么时候是异步?
这里的“异步”不是说异步代码实现. 而是说 react 会先收集变更,然后
再进行统一的更新. setState 在原生事件和 setTimeout 中都是同步的. 
在合成事件和钩子函数中是异步的. 在 setState 中, 会根据一个
isBatchingUpdates 判断是直接更新还是稍后更新, 它的默认值是
false. 但 是 React 在 调 用 事 件 处 理 函 数 之 前 会 先 调 用
batchedUpdates 这 个 函 数 , batchedUpdates 函 数 会 将
80
isBatchingUpdates 设置为 true. 因此, 由 react 控制的事件处理过程, 
就变成了异步(批量更新).
186. React 事件机制跟原生事件有什么区别?
React 的事件使用驼峰命名, 跟原生的全部小写做区分.不能通过
return false 来阻止默认行为, 必须明确调用 preventDefault 去阻止浏
览器的默认响应.
187. React 事件中为什么要绑定 this 或者要用箭头函数?
事实上, 这并不算是 react 的问题, 而是 this 的问题. 但是也是
react 中 经常 出现 的问 题 . 因 此也 讲一 下<button type="button" 
onClick={this.handleClick}>Click Me</button>这里的 this 是当事件被触
发时进行绑定的. this 的值会回退到默认绑定,即值为 undefined,
这是因为类声明和原型方法是以严格模式运行。我们可以使用 bind 
绑定到组件实例上. 而不用担心它的上下文.因为箭头函数中的 this 
指向的是定义时的 this,而不是执行时的 this. 所以箭头函数同样也
可以解决.
188. 谈谈 react 中的事件机制
在组件挂载的阶段, 根据组件生命的 react 事件, 给 document 添加
事件 addEventListener, 并添加统一的事件处理函数 dispatchEvent. 将
所有的事件和事件类型以及 react 组件进行关联, 将这个关系保存
在一个 map 里. 当事件触发的时候, 首先生成合成事件, 根据组
81
件 id 和事件类型找到对应的事件函数, 模拟捕获流程, 然后依次触发
对应的函数.
189. 谈谈 jsx 的原理
<div>Hello ConardLi</div>
实际上, babel 帮我们将这个语法转换成
React.createElement('div', null, `Hello ConardLi`)
190. Jsx 在书写的时候和 html 有什么不同?
必须有一个根标签在最外层包裹(因为这里的标签需要babel 编译, 编
译成 React.createElement(‘标签名’,’属性对象’, ’内容’) )
双标签和单标签(<br/>,<hr/>)都必须闭合, 否则无法通过编译
191. 在 jsx 中如果非要创建多个平行标签, 该如何处理? 
在 jsx 的最外层使用<></>进行包裹;
或者使用<React.Fragment></React.Fragment>标签进行包裹; 
两种方式本质是一样的, 底层都是通过
document.createDocumentFragment()创建了一个虚拟 dom 标签.
82
Angular
192. Angular 脚手架如何快速创建一个组件? 
ng g component [目录名/组件名]
193. Angular 中模块和组件之间有什么样的关系?
一个 angular 应用默认必须包含一个模块, 这个模块一般称为根模块, 
这个根模块一般必须包含一个组件, 这个组件称为根组件, 应用启动
的时候, 会默认加载根组件. 一个应用中可以声明多个模块, 将不同的
功能和页面组件注册在不同的模块中, 但是这些模块必须直接或间接
的注入到中根模块中. 使用模块可以将一个复杂的应用分成很部分, 
每部分有包含各自不通过的功能组件, 从而构成一个完整的应用.
前端构建工具 
194. 你了解到前端有哪些项目构建工具? 
webpack, gulp,grunt
195. webpack 和 gulp 在进行代码合并的时候还有什么不同?
webpack 是基于 commonjs 模块化规范进行代码合并, 而 gulp 只是简
单的代码合并.
83
const path=require('path');
const HtmlWebapckPlugin=require('html-webpack-plugin'); 
const htmlPlugin=new HtmlWebapckPlugin({
template:path.join( dirname,'src/index.html'), 
filename:'index.html'
});
module.exports={
// 打包模式, 可值:development(开发模式),production(生产模式) 
mode:'development',
// 插件配置节点
plugins:[
// html-webpack-plugin 作用:根据模板,在内存中创建一个 html 页面
htmlPlugin
],
resolve:{
// 配置省略的文件后缀
extensions: ['.js', '.jsx', '.json'],
// 配置根路径
alias:{'@':path.join( dirname,'./src')}
},
module:{
196. 列举几个 gulp 中常用的插件? 
合并文件: gulp-concat;
压缩 js: gulp-uglify;
文件重命名: gulp-rename; 
压 缩 css: gulp-minify-css 
压缩 html: gulp-hmltmin
启动开发服务器: gulp-connect
拷贝文件: gulp-copy
197. webpack 有哪些常见的配置? 
webpack.config.js:
84
微信小程序 
198. 微信小程序目前有几种主流的开发模式? 
微信官方:
原生方式;
// 配置 loader 
rules:[ {
test:/\.js|jsx$/, 
use:'babel-loader', 
exclude:/node_modules/
},
{
test: /\.scss$/, 
use: [
'style-loader', {
loader: 'css-loader', 
options: {
modules: {
localIdentName: '[name]-[local]-[hash:5]'
} }
},
'sass-loader'
]
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/, 
loader: 'url-loader', // 需 要 依 赖 file-loader 
options: {
limit: 10000
} } ] } }
85
wepy(微信官方推出的开发框架, 为了迎合目前主流前端框架的语法
和提高开发效率);
第三方公司:
mpvue(使用 vue 的语法开发小程序, 是一个阉割版的 vue)
uni-app(使用 vue 的语法进行开发, 是一个阉割版的 vue, 据说一套代
码可以编译出运行在多个平台的应用)
199. 简单介绍微信小程序的开发过程
首先得注册以为微信小程序, 因为小程序开发过程中需要一个 appid; 
其次下载腾讯官方的开发者工具(开发者工具必须使用个人微信登录), 
小程序只能运行在开发这工具或者微信应用内部;
创建应用, 填入申请的 appid, 即可快速生成小程序的项目结构.
200. 微信小程序中的 tabbar 导航如何制作
小程序中的 tabbar 底部导航是配置出来的, 只需要在应用配置文件
中添加一个 tabbar 配置阶段, 按照官方文档配置即可, tabbar 数量至
少 2, 最多 5.
201. 微信小程序中如何实现页面跳转? 
小程序页面跳转:
使用组件<navigator url=../home/home”>目标页面</navigator>
使用 api: wx.navigateTo({url:../home/home’})
86
wx.request({
Tabbar 页 面 跳 转 : 
wx.switchTabbar({url:../index/index’})
使用组件<navigator url=../home/home” open-type=”switchTab”>目标
页面</navigator>
202. 简单描述微信小程序的生命周期?
小程序的生命周期分为应用生命周期和页面生命周期. 
应用生命周期:
onLaunch: 应用启动, 只执行一次;
onShow: 应用切换到前台;
onHide: 应用切换到后台模式;
noError: 运行阶段出现错误;
onPageNotFound: 找不到页面
页面生命周期:
onLoad: 页面开始加载;
onReady: 页面加载完毕;
onShow: 页面进入焦点状态;
onHide: 页面进入后台状态
203. 微信小程序中如何请求数据接口? 
通过 wx.request
87
204. 如何优化小程序代码包的体积?
分包加载,使用分包加载可以让小程序代码包体积达到 8M(最多四个
分包,每个分包最大 2M);将资源文件尽量放在远程服务器端.
205. 你了解到微信小程序有哪些组件库?
Vant Weapp, iview Weapp, minui, WeUI, iview-mpvue
TypeScript
206. Typescript 中有哪些数据类型?
number(数值), string(字符型), boolean(布尔), object(对象),
undefined(未定义), null(空性), any(任意类型), never, 元组, 枚举, 数 组
207. Typescript 和 javascript 的区别?
url: 'test.php', //仅为示例,并非真实的接口地址
data: {
x: '',
y: ''
},
header: {
'content-type': 'application/json' // 默认值
},
success(res) 
{ console.log(res.data) }
})
88
Typescript 是 javascript 的一个超集, 是 es6 的实现, 支持所有 es6 的语
法, Typescript 只是在开发过程中编写的一种中间语言, 浏览器并不能
直接解析 Typescript, 上线以后需要将 Typescript 转换成 javascript.
208. 什么是装饰器?
代码版本控制工具 
209. 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 获取)
89
210. git 和 svn 有什么不同?
git 是一个分布式仓库管理系统, 每个人本地都有一个本地仓库,svn 是
一个集中式仓库管理系统, 仓库只有一个. svn 一般需要服务端给每个
人分配账号和密码, git 是使用 ssh 公钥/秘钥对来区分不同程序员的.
211. git 有哪些常用的图形界面客户端工具? 
Sourcetree, TortoiseGit
212. 在线 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/)
服务器编程 
NodeJS
213. Nodejs 中有哪些常用内置模块?
http; fs(文件系统); path(路径); querystring(查询字符串); url(解析 url)
90
214. 常用第三方模块
express; mysql(操作 mysql); cookie-parser(解析 cookie 的中间件); 
express-session(处理 session); crypt(加密模块)
215. Express 框架如何快速创建一个服务器?
216. Express 中路由模块的使用步骤
// 引入 express
const express=require('express')
// 创建服务器
const app=express();
// 监听路由
app.get('/',(req,res)=>{ res.
send('server running');
})
// 启动服务器
app.listen('3000',()=>{
console.log('server running at http://localhost:3000')
});
var express = require('express')
// 1. 创建一个路由容器
var router = express.Router() 
router.get('/get', function (req, res) {
res.send('请求了/get')
})
router.get('/list', function (req, res) {
res.send('请求了 /list')
})
router.post('/add', function (req, res) {
res.send('请求了 /add')
})
// 创建服务器
91
217. 使用 http 模块快速开启一个 web 服务器
Hybird(混合) APP
218. 目前流行的混合 App 开发方式
Appcan, Hbuilder(X), ApiCloud, 这几中方式大同小异, 都是通过网页的
方式开发 app, 然后通过开发工具将代码上传到远程服务器进行在线
打包, 开发工具本身会提供一些基础的 api 来帮助我们操作移动终端.
219. 什么是 Ionic 和 cordova?
const app=express();
// 注册路由中间件
app.use(router)
// 启动服务器
app.listen('3000',()=>{
console.log('server running at http://localhost:3000')
});
var http = require('http'); 
http.createServer(function (request, response) {
// 发送 HTTP 头部
// HTTP 状态值: 200 : OK
// 内容类型: text/plain
response.writeHead(200, { 'Content-Type': 'text/plain' });
// 发送响应数据 "Hello World" 
response.end('Hello World\n');
}).listen(8888);
92
Ionic 是一个专门针对移动端的组件库, 主要应用于 angular 系列框架
的开发中.
cordova 是一个移动应用打包工具, 可以将使用 angular+Ionic 开发的
移动端网页打包成可以在移动终端中安装的app 应用, cordova 提供了
一些基础 api( 比如读取手机通讯录, 获取摄像头权限...), 对于移动终
端的一些操作, 必须调用 codorva 提供的基础 api 才能完成.
使用 Ionic+cordova 可以实现移动端混合 app 的开发.
220. 什么是 react-native?
react-native 是 facebook 公司基于 react 的语法设计的一个开发原生移
动 app 的解决方案, 可以实现维护一套代码, 即可打包出可以运行在
安卓和苹果上的移动应用. 性能层面几乎和原生方式开发的应用接
近.
221. 什么是 flutter?
Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质
量的原生用户界面。 Flutter 可以与现有的代码一起工作。在全世界,
Flutter 正在被越来越多的开发者和组织使用,并且 Flutter 是完全免
费、开源的。学习 flutter 必须先学习 dart 语言, dart 是谷歌针对移动
端开发设计的一门开发语言, 目的是替代 javascript 的功能.
222. 什么是 weex?
93
Weex 是使用 vue 的语法来开发原生 app, 可以使用一套代码, 打包出
运行在安卓和苹果两个操作系统上的移动应用,需要在本地配置打包
环境, 和react-native 的工作原理类似. 性能层面几乎和原生方式开发
的应用接近.
223. 你所了解到的产品原型和设计图的共享平台有哪些? (产品原型和设计图的共享平台,可以帮助互联网团队更好地管理文档
和设计图。可以实现在线展示网页原型,自动生成设计图标注,与团队
共享设计图,展示页面之间的跳转关系, 前端程序员可以从该平台上
直接下载设计师设计好的设计图的切片, 并且可以在线查看设计图标
注信息)
常用产品原型共享平台有: 蓝湖, 墨刀, xiaopiu, Mockplus
实际开发相关 
224. 商城的购物车是怎么实现的?
商城购物车一般会写在本地存储,比如cookie 或者localStorage 中,会采
用数组格式的字符串来存储,主要会存储商品id, 商品名称, 商品价格, 
商品数量等信息(当然商品价格等敏感信息后期还是以后端为准, 此
处存储只是为了方便在页面展示), 如果过要考虑兼容问题, 建议存储 在 cookie (因为 localStorage 低版本的浏览器不支持).如果不考兼容
问题, 使用 localStorage 性能会更好. 购物车可以在用户未登录的状
态就可以添加, 也可以在用户登录以后再添加, 这个完全取决于具
94
体业务场景.
225. 前后端分离的项目如何实现登录状态的保持?
前后端分离的项目一般会使用 token 实现登录状态保持.
token 其实就是一个随机字符串, 当用户在登录页面输入账号和密码
后, 前端将账号密码发送给后端, 后端校验完账号和密码后, 会生成
一个随机的不重复的字符串(即 token), 并将其响应给前端, 前端拿到
该 token 后, 需要在客户端进行持久化(一般会写在 localStorage 或者
sessionStorage 中, 如果是 SPA 会存储在 sessionStorage 中, 如果是
MPA 则储存在 localStorage 中), 那么下次在向后端数据接口发送请求
的时候, 一般需要将 token 一并发送给后端数据接口, 后端数据接口
会对 token 进行校验, 如果合法则正常响应请求, 如果不合法, 则提示
未登录. 前端则根据本地存储中是否存在 token 判断用户是否处于登
录状态.
226. 前后端分离开发的后台管理系统一般如何实现权限管理?
首先某个角色有哪些权限肯定是事先配置好的, 并且存储在了数据库
里. 当某个账号登录后, 后端数据接口则需要返回该账号对应角色的
权限列表, 前端则需要根据该权限列表, 动态渲染管理系统的导航,然后端数据接口也会做二次权限校验(当某一个角色请求一个自己没
有的授权的数据接口或页面的时候, 后端数据接口也不会正常响应).
95
const 
lang={ zh
:{
mainNavi:[ "首页", "成功案例", "关于我们", "联系我们", "注册", "登录" ]
},
en:{
mainNavi:[
"home",
"succss cases", 
"about me", 
"concat us", 
"register", 
"login"
] }
227. 如何通过最原始的方式实现一个多语言版的网站?
简单来说,一般是通过配置语言包来实现的, 对于一个多语言的版的
网页, 并不一定是网页上所有的地方都需要实现多语言, 可能只是某
些关键的导航部分会实现多语言. 所以可以准备一个 json 配置文件, 
结构大体如下(只是简单举例):
当用户选择语言后, 可以将用户选择的语言类型存储在本地存储中, 
接着可以根据语言类型,从该语言配置文件中获取对应的配置节点, 
动态在页面上输出.
228. 如何实现从列表页跳入详情页,并从详情页面返回列表页时,96
动条还在当时的位置,并且数据不刷新?
为了保证返回时,我们还能回到刚才的位置,那么就需要做本地数据
存储。[考虑到保证数据和上次用户看到的一致]本地缓存的字段有页
码、点击的位置(滚动条的位置),列表数据(具体字段,请自行结
合实际) 进行本地缓存。合理的使用本地缓存数据有 cookie 、
sessionStorage,至于为啥要用两个,可以自行查阅,着重看一下存储
大小的限制问题当从详情返回列表时,首先从缓存中取页码、点击的
位置(滚动条的位置),列表数据,如果有位置、列表数据,则直接
将列表数据渲染到页面,并滚动到存储的位置点.
229. 微信小程序中如何实现页面后退时重新刷新页面?
在后退页面的 onShow 方法中手动调用一下 onLoad 方法, 代码如下
230. Vue 开发中如果由于某种特殊原因数据更新之后, 页面层没有
同步更新, 该如何处理?
调用 vm.$forceUpdate()方法强制刷新页面, 该方法可以迫使 Vue 实
例重新渲染.
231. Vue 中如何动态设置页面的 title 标题?
Page({
onShow(){ this.onLoad(
);
}
});
97
const router = new 
VueRouter({ routes: [...],
scrollBehavior (to, from, savedPosition) {
// return 期望滚动到哪个的位置
232. 在 vue 中,当切换到新路由时,想要页面滚到顶部,或者页面
后退时,想保持原先的滚动位置, 该如何实现?
const router = new 
Router({ routes: [
{ /* (首页)默认路由地址 */ 
path: '/',
component: login, 
meta: {
title: '首页入口' }
},
{
path: '/apply', 
component: apply, 
meta: {
title: '申请' }
},
{ /* Not Found 路由,必须是最后一个路由 */ 
path: '*',
component: NotFound, 
meta: {
title: '找不到页面' } } ]
});
router.beforeEach((to, from, next) => {
/* 路由发生变化修改页面 title */ 
if (to.meta.title) {
document.title = to.meta.title
}
next()
})
98
scrollBehavior 方 法 接 收 to 和 from 路 由 对 象 。 第 三 个 参 数
savedPosition 当且仅当通过浏览器的前进/后退按钮触发时才可用。
这个方法返回滚动位置的对象信息,长这样:{ x: number, y: number }
233. vue 项目在开发阶段如何解决跨域请求数据? 
使用 vue-cli-3.0 版本创建的项目解决跨域请求数据: 
第一步: 在项目根目录下创建 vue.config.js
第二步: 在 vue.config.js 中添加如下配置节点
// 返回原来的位置
// return savePosition
// 返回页面顶部
return { x: 0, y: 0 } }
})
module.exports = {
// 开发服务器配置节点
devServer: 
{ open: 
true,
host: 'localhost', 
port: 8081,
https: false, 
hotOnly: false, 
proxy: { // 配置跨域
'/api': {
// 数据接口服务器地址
target: 'http://localhost:5001/api/', 
ws: true,
changOrigin: true, 
pathRewrite: {
'^/api': ''
} } }
99
 

免责声明:该文来自传智播客,仅供学习使用,禁止用于商业用途,禁止转载,否则追究法律责任!

文中难免有错误,获取完整版pdf文档关注微信公众号“51学代码”,回复“前端面试”获取资料。


文章作者: JinJunzheng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 JinJunzheng !
评论
评论
  目录