一、前端基础阶段
1、为什么一个网页中只允许有一个h1标签?
答案:h1 代表大标题,一个网页中只能有一个大标题,不能拥有多个带标题(就跟一篇文章一样,一篇文章都是一个大标题,不会有多个大标题)
2、CSS标准盒模型包含哪些?
答案:标准盒模型 border, padding, content(内容), margin
3、如何用纯 CSS 创建一个三角形?
#box{
width: 0;
height: 0;
border-width: 20px;
border-style: solid;
border-color: transparent transparent red transparent;
}
4、清除浮动有哪些方式?
答案:
- 给父元素div定义height
- 在元素结尾处加空div标签clear:both
- 父元素div定义伪类:after :before和zoom
- 父元素div定义overflow:hidden
5、说一说你对语义化的理解
答案:
- 用正确的标签做正确的事情!
HTML
语义化就是让页面的内容结构化,便于对浏览器、搜索引擎解析;- 在没有样式
CSS
情况下也以一种文档格式显示,并且是容易阅读的; - 有利于
SEO
优化; - 使阅读源代码的人对网站更容易将网站分块儿,便于阅读维护理解;
6、简述一下src与href的区别
答案:
src
用于替换当前元素,href用于在当前文档和引用资源之间确立联系。src
是source
的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求src
资源时会将其指向的资源下载并应用到文档内,例如js
脚本,img
图片和frame
等元素<script src ="js.js"></script>
当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等元素也如此,类似于将所指向资源嵌入当前标签内。这也是为什么将js脚本放在底部而不是头部href
是Hypertext Reference
的缩写,指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,如果我们在文档中添加<link href="common.css" rel="stylesheet"/>
那么浏览器会识别该文档为css
文件,就会并行下载资源并且不会停止对当前文档的处理。这也是为什么建议使用link
方式来加载css
,而不是使用@import
方式
7、css3有哪些新特性?
- 新增选择器
p:nth-child(n){color: rgba(255, 0, 0, 0.75)}
- 弹性盒模型
display: flex;
- 媒体查询
@media (max-width: 480px) {.box: {column-count: 1;}}
- 圆角
border-radius: 5px;
- 渐变
background:linear-gradient(red, green, blue);
- 阴影
box-shadow:3px 3px 3px rgba(0, 64, 128, 0.3);
- 转换
- 旋转
transform: rotate(20deg);
- 倾斜
transform: skew(150deg, -10deg);
- 位移
transform: translate(20px, 20px);
- 缩放
transform: scale(.5);
- 旋转
- 平滑过渡
transition: all .3s ease-in .1s;
- 动画
@keyframes anim-1 {50% {border-radius: 50%;}} animation: anim-1 1s;
8、如何垂直居中一个浮动元素?
答案:
/**方法一:已知元素的高宽**/
#div1{
background-color:#6699FF;
width:200px;
height:200px;
position: absolute; //父元素需要相对定位
top: 50%;
left: 50%;
margin-top:-100px ; //自身一半的height,width
margin-left: -100px;
}
/**方法二:**/
#div1{
width: 200px;
height: 200px;
background-color: #6699FF;
margin:auto;
position: absolute; //父元素需要相对定位
left: 0;
top: 0;
right: 0;
bottom: 0;
}
9、什么是 css sprite(精灵图)是什么?,有什么优点?
答案:
- 概念:将多个小图片拼接到一个图片中。通过
background-position
和元素尺寸调节需要显示的背景图案。 - 优点:
- 减少
HTTP
请求数,极大地提高页面加载速度 - 增加图片信息重复度,提高压缩比,减少图片大小
- 更换风格方便,只需在一张或几张图片上修改颜色或样式即可实现
- 减少
10、为什么要初始化CSS样式?
答案:
为了保证各个浏览器显示一致(代码兼容性),我们需要做一些初始化样式操作。
11、什么是bootstrap
?为什么要使用bootstrap
?
答案:
什么是bootstrap
?
Bootstrap
是基于HTML
、CSS
、JAVASCRIPT
的开源框架,它简洁、直观、强悍、灵活,使得Web
开发更加快捷,- 用于开发响应式布局、移动设备优先的
WEB
项目。
为什么使用 Bootstrap
?
- 跨设备
- 跨浏览器(
chrome
,IE9
以上,Firefox
,Safari
,Opera
...) - 响应式布局
- 具有实用性强的组件
12、display有哪些值?并说明它们的作用
答案:
block
转换成块状元素。inline
转换成行内元素。none
设置元素不可见。inline-block
象行内元素一样显示,但其内容象块类型元素一样显示。- ……
13、css有哪些属性可以继承?
答案:
1、字体系列属性
font-family:字体系列
font-weight:字体的粗细
font-size:字体的大小
font-style:字体的风格
2、文本系列属性
text-align:文本水平对齐
line-height:行高
color:文本颜色
3、元素可见性:
visibility:控制元素显示隐藏
……
14、定位的值有哪几种?区别是什么?
答案:
- static(静态定位):默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。
- relative(相对定位):生成相对定位的元素,通过top,bottom,left,right的设置相对于其正常(原先本身)位置进行定位。可通过z-index进行层次分级。
- absolute(绝对定位):生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。可通过z-index进行层次分级。
- fixed(固定定位):生成绝对定位的元素,相对于浏览器窗口进行定位。元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。可通过z-index进行层次分级。
15、在Less中如何表示(声明)变量?
答案:
需要使用@符号声明变量, 并使用冒号:来分配变量中的特定值。还必须在变量的值之后添加分号;
@color:#800080;
div {
color: @color;
}
16、请列举几种隐藏元素的方法
答案:
- visibility: hidden;这个属性只是简单的隐藏某个元素,但是元素占用的空间任然存在。
- display: none;元素会变得不可见,并且不会再占用文档的空间。
- position: absolute;使元素脱离文档流,处于普通文档之上,给它设置一个很大的left负值定位,使元素定位在可见区域之外。
- opacity: 0;一个CSS3属性,设置0可以使一个元素完全透明,制作出和visibility一样的效果。
17、行内元素有哪些?块级元素有哪些?
答案:
行内元素:<a>
、<span>
、<img>
、<input>
、<button>
等
块级元素:<div>
、<p>
、<form>
、<ul>
、<li>
、<table>
等
18、什么时候使用浮动?什么时候使用定位?
答案:
使用浮动: 想让块元素并排显示在一行的时候,可以使用浮动,比如:网站中的导航元素并排显示、网站中的图片大盒子(div嵌套img)并排显示在一行等等。
19、块级元素和行内元素的区别?
答案:
块级元素会独占一行,默认情况下,其宽度自动填满其父元素宽度。 行内元素不会独占一行,相邻的行内元素会排列在同一行里,直到一行排不下,才会换行,其宽度随元素的内容而变化。
- 块级元素可以设置width,height属性
- 行内元素设置width,height属性无效,它的长度高度主要根据内容决定
- 块级元素即使设置了宽度,仍然是独占一行
- 块级元素可以设置margin和padding属性
- 行内元素的margin和padding属性,水平方向的padding-left,padding-right,margin-left,margin- right都产生边距效果,但竖直方向的padding-top,padding-bottom,margin-top,margin-bottom却不会产生边距效果
- 块级元素对应于display:block
- 行内元素对应于display:inline
20、<img>
的title和alt有什么区别?
答案:
- alt 是图片加载失败时,显示在网页上的替代文字;
- title 是鼠标放上面时显示的文字。
- alt是img必要的属性,而title不是。
21、 margin和padding分别适合什么场景使用?
答案:
- 需要在
border
外侧添加空白,且空白处不需要背景(色)时,使用margin
- 需要在
border
内测添加空白,且空白处需要背景(色)时,使用padding
22、flex布局优缺点?
Flex 是 Flexible Box 的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。 任何一个容器都可以指定为 Flex 布局。
优点:容易上手,根据flex规则很容易达到某个布局效果。
缺点:浏览器兼容性比较差,只能兼容到ie9及以上。
23、Less是什么?为什么要使Less?
Less 是CSS预处理器。less是一种特殊的语法,用于编译成CSS,Less 将CSS赋予了动态语言的特性,如变量,继承,运算等。
- 减少重复写代码,开发更快
- 完全兼容 CSS 代码
- 结构清晰,便于扩展(嵌套功能)
- 可以方便地屏蔽浏览器私有语法差异(函数功能)
24、CSS书写顺序
- 位置属性(position, top, right, z-index, display, float等)
- 大小(width, height, padding, margin)
- 文字系列(font, line-height,等)
- 颜色、背景(color、background, border等)
- 其它(animation, transition等)
二、前端基本功阶段
1、 以下 console.log(a) 打印的结果是什么?为什么打印出这个结果?
console.log(a) var a = 10;
答案:undefined,因为变量声明提升,会把a提升到console.log()上面,上面的a 的值是undefined,所以打印undefined
2、以下 console.log(a) 打印的结果是什么?为什么打印出这个结果?
var a = 10; function a() {} console.log(a)
答案:10,因为有函数声明提升,函数声明优先于变量声明提升,所以提升之后functiona(){} 会在 var a 的前面去。所以打印10。
3、什么是变量?
变量就是一个容器,可以存储不同类型的数据。
4、以下 console.log(a) 打印的结果是什么?为什么打印出这个结果(为什么不打印undefined?)?
function a() {} console.log(a) var a = 10;
答案:ƒ a() {},原因:
function a() {}
console.log(a)
var a = 10;
以上代码,JS预解析如下:
function a(){} // a 在这里已经声明了,a 是一个函数
var a; // a 在这里再次声明,重复声明的变量会被忽略,所以这里的代码不执行,
console.log(a) // 所以这里打印 ƒ a() {}
a = 10;
5、 null,undefined 的区别?
答案:
undefined
表示不存在这个值。undefined
:是一个表示"无"的原始值或者说表示"缺少值",就是此处应该有一个值,但是还没有定义。当尝试读取时会返回undefined
- 例如变量被声明了,但没有赋值时,就等于
undefined
null
表示一个对象被定义了,值为“空值”null
: 是一个对象(空对象, 没有任何属性和方法)- 例如作为函数的参数,表示该函数的参数不是对象;
- 在验证
null
时,一定要使用===
,因为==
无法分别null
和undefined
6、原始类型有哪几种?null 是对象吗?
答案:
在 JS 中,存在着 6 种原始值,分别是:
boolean
null
undefined
number
string
symbol
首先原始类型存储的都是值,是没有函数可以调用的,比如undefined.toString()
虽然'1'.toString()
是可以使用的。但是其实在这种情况下,'1'
已经不是原始类型了,而是被强制转换成了String
类型也就是对象类型,所以可以调用toString
函数。
对于null
来说,很多人会认为他是个对象类型,但其实这是错误的。虽然typeof null
会输出object
,但是这只是 JS 存在的一个悠久 Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000
开头代表是对象,然而null
表示为全零,所以将它错误的判断为object
。
7、 请解释什么是事件代理?
答案:
- 事件代理(
Event Delegation
),又称之为事件委托。是JavaScript
中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。使用事件代理的好处是可以提高性能 - 可以大量节省内存占用,减少事件注册,比如在
table
上代理所有td
的click
事件就非常棒 - 可以实现当新增子对象时无需再次对其绑定
8、谈一谈闭包
答案:
- 闭包就是能够读取其他函数内部变量的函数
- 闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域
- 闭包的特性:
- 函数内再嵌套函数
- 内部函数可以引用外层的参数和变量
- 参数和变量不会被垃圾回收机制回收
对闭包的理解
- 使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念
- 闭包 的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中
- 闭包的另一个用处,是封装对象的私有属性和私有方法
- 好处:能够实现封装和缓存等;
- 坏处:就是消耗内存、不正当使用会造成内存溢出的问题
使用闭包的注意点
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露
- 解决方法是,在退出函数之前,将不使用的局部变量全部删除
9、基本数据类型和引⽤类型在存储上的区别?
答案:
基本数据类型存储在栈上,引⽤类型存储在堆上
10、 谈一谈let与var的区别?
答案:
let
命令不存在变量提升,如果在let
前使用,会导致报错- 如果块区中存在
let
和const
命令,就会形成封闭作用域 - 不允许重复声明,因此,不能在函数内部重新声明参数
11、以下输出的结果是?为什么?
let c = { greeting: 'Hey!' }
let d
d = c
c.greeting = 'Hello'
console.log(d.greeting)
答案:
在 JavaScript 中,当设置两个对象彼此相等时,它们会通过引用进行交互。
首先,变量 c
的值是一个对象。接下来,我们给 d
分配了一个和 c
对象相同的引用。
因此当我们改变其中一个对象时,其实是改变了所有的对象。
12、call, apply的相同点和不同点
答案:
call
和apply
都是为了解决改变this
的指向。作用都是相同的,只是传参的方式不同。- 除了第一个参数外,
call
可以接收一个参数列表,apply
只接受一个参数数组
let a = {
value: 1
}
function getValue(name, age) {
console.log(name)
console.log(age)
console.log(this.value)
}
getValue.call(a, '张三', '24')
getValue.apply(a, ['张三', '24'])
13、什么是JavaScript原型、原型链 ? 有什么特点?
答案:
- 每个对象都会在其内部初始化一个属性,就是
prototype
(原型),当我们访问一个对象的属性时 - 如果这个对象内部不存在这个属性,那么他就会去
prototype
里找这个属性,这个prototype
又会有自己的prototype
,于是就这样一直找下去,也就是我们平时所说的原型链的概念 - 关系:
instance.constructor.prototype = instance.__proto__
- 特点:
JavaScript
对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变
- 当我们需要一个属性的时,
Javascript
引擎会先看当前对象中是否有这个属性, 如果没有的 - 就会查找他的
Prototype
对象是否有这个属性,如此递推下去,一直检索到Object
内建对象 - 原型:
JavaScript
的所有对象中都包含了一个[__proto__]
内部属性,这个属性所对应的就是该对象的原型- JavaScript的函数对象,除了原型
[__proto__]
之外,还预置了prototype
属性 - 当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型
[__proto__]
。
- 原型链:
- 当一个对象调用的属性/方法自身不存在时,就会去自己
[__proto__]
关联的前辈prototype
对象上去找 - 如果没找到,就会去该
prototype
原型[__proto__]
关联的前辈prototype
去找。依次类推,直到找到属性/方法或undefined
为止。从而形成了所谓的“原型链”
- 当一个对象调用的属性/方法自身不存在时,就会去自己
- 原型特点:
JavaScript
对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变
14、Javascript如何实现继承?
答案:
- 构造继承
- 原型继承
- 类继承
- ……
15、JavaScript的组成?
答案:
由以下三部分组成:
ECMAScript(核心):
JavaScript` 语言基础DOM
(文档对象模型):规定了访问HTML
和XML
的接口BOM
(浏览器对象模型):提供了浏览器窗口之间进行交互的对象和方法
16、 $(this) 和 this 关键字在 jQuery 中有何不同?
答案:
$(this)
返回一个 jQuery
对象,你可以对它调用多个 jQuery
方法,比如用 text()
获取文本,用val()
获取值等等。而 this
代表当前元素,它是 JavaScript
关键词中的一个,表示上下文中的当前DOM
元素。你不能对它调用 jQuery
方法,直到它被 $()
函数包裹,例如 $(this)
。
17、== 和 ===有什么区别?
答案:
===
叫做严格相等,是指:左右两边不仅值要相等,类型也要相等,例如'1'===1
的结果是false
,因为一边是string
,另一边是`number
==
不像===
那样严格,对于一般情况,只要值相等,就返回true,但==还涉及一些类型转换,它的转换规则如下**
- 两边的类型是否相同,相同的话就比较值的大小,例如
1==2
,返回false
- 判断的是否是
null
和undefined
,是的话就返回true - 判断的类型是否是
String
和Number
,是的话,把String
类型转换成Number
,再进行比较 - 判断其中一方是否是
Boolean
,是的话就把Boolean
转换成N
umber`,再进行比较 - 如果其中一方为
Object
,且另一方为String
、Number
或者Symbol
,会将Object
转换成字符串,再进行比较
18、根据如下代码,请问 console.log(a == b) 和 console.log(a === b) 打印的结果分别是什么?
var a = "42";
var b = a * 1;
console.log(a == b)
console.log(a === b)
答案:
var a = "42";
var b = a * 1; // "42" 隐式转型成 42
a; // "42"
b; // 42 -- 是个数字!
console.log(a == b) // true == 只判断值是否相等
console.log(a === b) // false === 判断类型和值都要相等
19、new 的原理是什么?通过 new 的方式创建对象和通过字面量创建有什么区别?
调用new
的过程中会发生以上四件事情:
- 创建了一个新对象;
- 将这个新创建的对象,链接到原型;
- 执行构造函数方法,绑定 this,属性和方法被添加到this引用的对象中
- 返回新对象
根据以上几个过程,我们也可以试着来自己实现一个new
function create() {
let obj = {}
let Con = [].shift.call(arguments)
obj.__proto__ = Con.prototype
let result = Con.apply(obj, arguments)
return result instanceof Object ? result : obj
}
以下是对实现的分析:
- 创建一个空对象
- 获取构造函数
- 设置空对象的原型
- 绑定
this
并执行构造函数 - 确保返回值为对象
对于对象来说,其实都是通过new
产生的,无论是function Foo()
还是let a = { b : 1 }
。
对于创建一个对象来说,更推荐使用字面量的方式创建对象(无论性能上还是可读性)。因为你使用new Object()
的方式创建对象需要通过作用域链一层层找到Object
,但是你使用字面量的方式就没这个问题。
function Foo() {}
// function 就是个语法糖
// 内部等同于 new Function()
let a = { b: 1 }
// 这个字面量内部也是使用了 new Object()
20、var、let 、 const 的区别?
答案:
var
存在提升,我们能在声明之前使用。let
、const
不能在声明前使用var
在全局作用域下声明变量会导致变量挂载在window
上,其他两者不会let
和const
作用基本一致,但是后者声明的变量不能再次赋值
21、什么是函数的形参和实参?
答案:
形参相当于函数中定义的变量,实参是在运行时的函数调用时传入的参数。
形参就是函数声明时的变量, 实参是我们调用该函数时传入的具体参数。
22、 jQuery对象有什么特点?
答案:
- 只有
JQuery
对象才能使用JQuery
方法 JQuery
对象是一个数组对象
23、以下代码,打印的结果是,为什么?
console.log(a);
var a = 10;
function a(){};
答案:function a(){} ,原因如下:
以上代码,JS预解析如下:
function a(){} // a 在这里已经声明了,a 是一个函数
var a; // a 在这里再次声明,重复声明的变量会被忽略,所以这里的代码不执行,
console.log(a) // 所以这里打印 ƒ a() {}
a = 10;
24、以下代码,打印的结果是,为什么?
给定一个整数数组nums和一个整数目标值target,请在该数组中找出和为目标值的那两个整数,并返回它们的数组下标。
例如:var nums = [2, 8, 7, 15] ,target = 9; nums[0] + nums[2] == 9。 返回 2 ,7 [0,2]
var nums = [2、 8、 7、 15];
var target = 9;
for (var i = 0; i < nums.length; i++) {
for (var j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) {
console.log(nums[i], nums[j])
console.log([i, j])
}
}
}
25、重绘和回流?
当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。
区别:回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流。
当页面布局和几何属性改变时就需要回流,比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变
26、防抖和节流?
防抖:高频率触发的事件,在指定的单位时间内,只响应最后一次(只执行最后一次)
节流:高频率触发的事件,在指定的单位时间内,只响应第一次(在指定的时间内,只执行一次)
防抖和节流的使用场景:
防抖(debounce) 1.search搜索联想,用户在不断输入值时,用防抖来节约请求资源。 2.window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
节流(throttle) 1.鼠标不断点击触发,mousedown(单位时间内只触发一次) 2.监听滚动事件,比如是否滑到底部自动加载更多
三、前后端交互阶段
1、Ajax的核心是什么?
答案:XMLHttpRequest,因为创建ajax需要通过 XMLHttpRequest方法创建
2、什么是Ajax?Ajax作用是什么?
答案:AJAX = 异步 JavaScript 和 XML。 AJAX 是一种用于创建快速动态网页的技术。 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.
3、Ajax有那些优缺点?
答案:
- 优点:
- 通过异步模式,提升了用户体验.
- 优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用.
Ajax
在客户端运行,承担了一部分本来由服务器承担的工作,减少了大用户量下的服务器负载。Ajax
可以实现动态不刷新(局部刷新)
- 缺点:
- 安全问题
AJAX
暴露了与服务器交互的细节。 - 对搜索引擎的支持比较弱。
- 不容易调试。
- 安全问题
4、什么是跨域?如何解决跨域问题?
答案:
首先了解下浏览器的同源策略 同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS
、CSFR
等攻击。所谓同源是指"协议+域名+端口"三者相同,只要三者有任意一个不同,就是非同源,即跨域。(非同源就是跨域)
- 通过jsonp跨域
- proxy跨域(在项目中配置proxy跨域,后面在学习Vue项目时会学到,这个不推荐,因为不能在生产阶段使用,只能在开发阶段使用)
- 后端(node、java、php、python等)在头部信息里面设置允许跨域的设置
- nodejs中间件代理跨域
- nginx代理跨域
5、JSONP原理是什么?JSONP的只限于什么请求?
JSONP
的原理很简单,就是利用 <script>
标签没有跨域限制的漏洞。通过 <script>
标签指向一个需要访问的地址并提供一个回调函数来接收数据当需要通讯时。
JSONP
使用简单且兼容性不错,但是只限于get
请求。
6、token一般是存放在哪里?
Token其实就是访问资源的凭证。
一般是用户通过用户名和密码登录成功之后,服务器将登陆凭证做数字签名,加密之后得到的字符串作为token。 它在用户登录成功之后会返回给客户端,客户端主要有这么几种存储方式:
- 存储在
localStorage
中,每次调用接口的时候都把它当成一个字段传给后台 - 存储在
cookie
中,让它自动发送,不过缺点就是不能跨域 - 拿到之后存储在
localStorage
中,每次调用接口的时候放在HTTP请求头的Authorization
字段里
7、手写 XMLHttpRequest 不借助任何请求库
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
// 这里的函数异步执行,可参考之前 JS 基础中的异步模块
if (xhr.readyState == 4) {
if (xhr.status == 200) {
alert(xhr.responseText)
}
}
}
xhr.open("GET", "/api", false)
xhr.send(null)
8、Git 中的三种状态
答案:
- 已修改 modified :表示修改了文件,但还没将修改的结果放到暂存区
- 已暂存 staged :表示对已修改文件的当前版本做了标记,使之包含在下次提交的列表中
- 已提交 committed :表示文件已经安全地保存在本地的 Git 仓库中
9、git常用命令
git提交文件
/*将单个文件添加到暂存区中*/
git add 'filename'
/*将当前所有文件添加到暂存区中*/
git add .
/*提交文件*/
git commit -m "comment"
/*添加并提交文件*/
git commit -a -m "comment"
Git分支操作(创建、删除、合并分支)
git branch //查看所有分支
git branch <name> //创建分支
git checkout <name> //切换分支
git checkout -b <name> //创建并切换分支
git branch -d <name> //删除分支,无法删除未被合并的分支
git branch -D <name> //强制删除分支,可以删除未被合并的分支
git merge <branch> //将branch分支合并到当前分支,当前分支拥有branch分支的记录,branch分支不变
git merge <branch1> <branch2> //将分支branch1合并到branch2
git查看状态或记录
git status // 查看当前状态
git log //显示当前分支的commit记录
回退
/*将HEAD移动到commit id对应的提交点*/
git reset <commit id>
/*工作区、暂存区和历史记录区都会被重置commit id提交点*/
git reset --hard <commit id>
10、常见的状态码有哪些?
答案:
状态码表示了响应的一个状态,可以让我们清晰的了解到这一次请求是成功还是失败,如果失败的话,是什么原因导致的,当然状态码也是用于传达语义的。如果胡乱使用状态码,那么它存在的意义就没有了。
2XX 成功
- 200 OK,表示从客户端发来的请求在服务器端被正确处理
- 204 No content,表示请求成功,但响应报文不含实体的主体部分
- 205 Reset Content,表示请求成功,但响应报文不含实体的主体部分,但是与 204 响应不同在于要求请求方重置内容
- 206 Partial Content,进行范围请求
3XX 重定向
- 301 moved permanently,永久性重定向,表示资源已被分配了新的 URL
- 302 found,临时性重定向,表示资源临时被分配了新的 URL
- 303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源
- 304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况
- 307 temporary redirect,临时重定向,和302含义类似,但是期望客户端保持请求方法不变向新的地址发出请求
4XX 客户端错误
- 400 bad request,请求报文存在语法错误
- 401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息
- 403 forbidden,表示对请求资源的访问被服务器拒绝
- 404 not found,表示在服务器上没有找到请求的资源
5XX 服务器错误
- 500 internal sever error,表示服务器端在执行请求时发生了错误
- 501 Not Implemented,表示服务器不支持当前请求所需要的某个功能
- 503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求
11、同步和异步的区别?
答案:
同步:当客户端发送请求给服务端,在等待服务端响应的请求时,客户端不做其他的事情。当服务端做完了才返回到客户端。这样的话客户端需要一直等待。用户体验不太友好。
异步:当客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情,这样节约了时间,提高了效率。
异步虽然好,但是有些问题是要用同步用来解决,比如有些东西我们需要的是拿到返回的数据在进行操作的(比如:登录功能)。这些是异步所无法解决的。
12、cookie和session的关系和区别?
答案:
1.为什么会用到cookie和session
由于http请求是一种无状态的请求,一旦数据交换完毕便会关闭请求,再次交换数据则要再次发起请求,所以服务端无法通过连接追踪会话,确定用户身份,而cookie和session则可以帮助服务端确定用户身份。
2.cookie运行流程
第一次登陆的时候,服务器返回一段数据(cookie)给浏览器,然后浏览器则需要把返回的数据存储起来。那么在第二次请求的时候,浏览器则需要发送存储起来的那段数据(cookie)给服务器,以至于让服务器确认访问用户的身份。
3.session的运行流程
而session则和cookie差不多,都是用来存储数据,确定用户身份。不同的是session是存储在服务器的,而cookie则是存储在电脑本地文件里的,一般第一次登陆的时候,服务器在存储session时会生成session_id,通过http请求头返回给浏览器,然后浏览器则会把session_id保存在cookie里,等到第二次请求的时候,浏览器则会发送session_id到服务器,服务器通过session_id获取到对应的数据来判断用户的身份。
13、XML和JSON的区别?
答案:
- 数据体积方面
JSON
相对于XML
来讲,数据的体积小,传递的速度更快些。
- 数据交互方面
JSON
与JavaScript
的交互更加方便,更容易解析处理,更好的数据交互
- 数据描述方面
JSON
对数据的描述性比XML
较差
- 传输速度方面
JSON
的速度要远远快于XML
14、使用npm有哪些好处?
答案:
通过NPM,你可以安装和管理项目的依赖,并且能够指明依赖项的具体版本号,可以通过package.json文件来管理项目信息,安装项目依赖等。
15、 HTTP 报文的组成部分
答案:
1、请求报文
- 请求行 ( http 方法 + 页面地址 + http 协议 + 版本)
- 请求头( key + value 值)
- 请求体(数据部分)
2、响应报文
- 状态行
- 响应头
- 响应体
16、AJAX技术体系的组成部分有哪些?
答案:
Ajax不是一个技术,它实际上是几种技术,每种技术都有其独特这处,合在一起就成了一个功能强大的新技术。Ajax包括: 1、Javascript——JavaScript是通用的脚本语言,而Ajax应用程序就是使用JavaScript来编写的。 2、CSS——CSS为Web页面元素提供了可视化样式的定义方法。Ajax应用中,用户界面的样式可以通过CSS独立修改。 3、DOM——通过JavaScript修改DOM,Ajax应用程序可以在运用时改变用户界面。 4、XMLHttpRequest对象——XMLHttpRequest对象允许Web程序员从Web服务器以后台的方式来获取数据。 5、XML——可扩展的标记语言(Extensible Markup Language)具有一种开放的、可扩展的、可自描述的语言结构,它已经成为网上数据和文档传输的标准。它是用来描述数据结构的一种语言,就正如他的名字一样。他使对某些结构化数据的定义更加容易,并且可以通过他和其他应用程序交换数据。 6、HTM——称为超文本标记语言,是一种标识性的语言。
17、HTTP协议是无状态还是有状态?
答案:
HTTP是一种不保存状态,即无状态 ( stateless )协议。 HTTP协议自身不对请求和响应之间的通信状态进行保存。 也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做持久化处理。 使用HTTP协议,每当有新的请求发送时,就会有对应的新响应产生。协议本身并不保留之前一切的请求或者响应报文的信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成如此简单的。
随着 WEB 的不断发展,因无状态而导致业务处理变得棘手的情况增多了。为了实现期望的保持状态功能,于是引入了 Cookie 技术。有了Cookie 再用HTTP协议通信,就可以管理状态了。
18、cookie 、 session 、token的区别?
答案:
cookie与session的区别
cookie数据存放在客户端上,session数据放在服务器上;
cookie不是很安全,且保存数据有限(单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie);
session一定时间内保存在服务器上,当访问增多,占用服务器性能。
session与token的区别
作为身份认证,token安全性比session好;
Session 认证只是简单的把User 信息存储到Session 里。 而Token 提供的是 认证 和 授权 ,认证是针对用户,授权是针对App 。其目的是让 某App有权利访问 某用户 的信息。
token与cookie的区别
Cookie是不允许垮域访问的,但是token是支持的, 前提是传输的用户认证信息通过HTTP头传输;
token就是令牌,比如你授权(登录)一个程序时,他就是个依据,判断你是否已经授权该软件;cookie就是写在客户端的一个txt文件,里面包括你登录信息之类的,这样你下次在登录某个网站,就会自动调用cookie自动登录用户名;session和cookie差不多,只是session是写在服务器端的文件,也需要在客户端写入cookie文件,但是文件里是你的浏览器编号.Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。
19、请描述一下 cookies,sessionStorage 和 localStorage 的区别?
答案:
cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)
cookie数据始终在同源的http请求中携带(即使不需要),记会在浏览器和服务器间来回传递
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
存储大小:
cookie数据大小不能超过4k sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大 有期时间:
localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据 sessionStorage 数据在当前浏览器窗口关闭后自动删除 cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
20、 CORS跨域的原理?
答案:
跨域资源共享(CORS
)是一种机制,是W3C标准。它允许浏览器向跨源服务器,发出XMLHttpRequest
或Fetch
请求。并且整个CORS
通信过程都是浏览器自动完成的,不需要用户参与。而使用这种跨域资源共享
的前提是,浏览器必须支持这个功能,并且服务器端也必须同意这种"跨域"
请求。通常是有以下几个配置:
- Access-Control-Allow-Origin
- Access-Control-Allow-Methods
- Access-Control-Allow-Headers
- Access-Control-Allow-Credentials
- Access-Control-Max-Age
PS:回答配置时,可以说出前三个即可。
21、常见的状态码有哪些?
答案:
2XX 成功
- 200 OK,表示从客户端发来的请求在服务器端被正确处理
- 204 No content,表示请求成功,但响应报文不含实体的主体部分
- 205 Reset Content,表示请求成功,但响应报文不含实体的主体部分,但是与 204 响应不同在于要求请求方重置内容
- 206 Partial Content,进行范围请求
3XX 重定向
- 301 moved permanently,永久性重定向,表示资源已被分配了新的 URL
- 302 found,临时性重定向,表示资源临时被分配了新的 URL
- 303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源
- 304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况
- 307 temporary redirect,临时重定向,和302含义类似,但是期望客户端保持请求方法不变向新的地址发出请求
4XX 客户端错误
- 400 bad request,请求报文存在语法错误
- 401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息
- 403 forbidden,表示对请求资源的访问被服务器拒绝
- 404 not found,表示在服务器上没有找到请求的资源
5XX 服务器错误
- 500 internal sever error,表示服务器端在执行请求时发生了错误
- 501 Not Implemented,表示服务器不支持当前请求所需要的某个功能
- 503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求
22、Post 和 Get 的区别?
答案:
- get是获取数据的,而post是提交数据的。
- GET 用于获取信息,是无副作用的,且可缓存, 而POST 用于修改服务器上的数据,有副作用,不可缓存。
四、前端框架阶段
1、请问 v-if 和 v-show 有什么区别?
答案:
①、编译过程: v-if 是 真正 的 条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性display。
②、编译条件: v-if 是惰性的:如果在初始渲染时条件为假,则什么也不做。直到条件第一次变为真时,才会开始渲染条件块。v-show不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
③、性能消耗: v-if有更高的切换消耗。v-show有更高的初始渲染消耗。
④、应用场景: v-if适合运行时条件很少改变时使用。v-show适合频繁切换。
2、vue中 key 值的作用
答案:用于 管理可复用的元素。因为Vue
会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。
3、Vue 组件中 data 为什么必须是函数?
答案:因为一个组件是可以共享的,但他们的data是私有的,所以每个组件都要return一个新的data对象,返回一个唯一的对象,不要和其他组件共用一个对象。
4、computed 和 watch 区别?什么时候使用计算属性,什么时候使用watch属性呢?
答案:
computed
是计算属性,依赖其他属性计算值,并且computed
的值有缓存,只有当计算值变化才会返回内容。watch
监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。- 所以一般来说需要依赖别的属性来动态获得值的时候可以使用
computed
,对于监听到值的变化需要做一些复杂业务逻辑的情况可以使用watch
。 - 能够使用computed属性实现的结果,就使用
computed
属性,不要使用watch
,因为watch
是一直在侦听数据的变化,对内存性能开销比较大,而计算属性是基于它们的依赖进行缓存的,所以从性能上比watch开销要小很多。 - 当需要执行异步操作的时候,就要使用
watch
属性,这个是computed
属性无法做到的。
5、组件中 data 什么时候可以使用对象?
答案:
- 组件复用时所有组件实例都会共享
data
,如果data
是对象的话,就会造成一个组件修改data
以后会影响到其他所有组件,所以需要将data
写成函数,每次用到就调用一次函数获得新的数据。 - 当我们使用
new Vue()
的方式的时候,无论我们将data
设置为对象还是函数都是可以的,因为new Vue()
的方式是生成一个根组件,该组件不会复用,也就不存在共享data
的情况了
6、vuex 是什么? 有哪几种属性?
答案:
Vuex
是一个专为Vue.js
应用程序开发的状态管理模式。- 有 5 种,分别是
state
、getter
、mutation
、action
、module
vuex 的 store 是什么?
vuex
就是一个仓库,仓库里放了很多对象。其中state
就是数据源存放地,对应于一般 vue 对象里面的datastate
里面存放的数据是响应式的,vue
组件从store
读取数据,若是store
中的数据发生改变,依赖这相数据的组件也会发生更新它通过mapState
把全局的state
和getters
映射到当前组件的computed
计算属性
vuex 的 getter 是什么?
getter
可以对state
进行计算操作,它就是store
的计算属性虽然在组件内也可以做计算属性,但是getters
可以在多给件之间复用如果一个状态只在一个组件内使用,是可以不用getters
vuex 的 mutation 是什么?
- 更改
Vuex
的store
中的状态的唯一方法是提交mutation
vuex 的 action 是什么?
action
类似于muation
, 不同在于:action
提交的是mutation
,而不是直接变更状态action
可以包含任意异步操作vue
中ajax
请求代码应该写在组件的methods
中还是vuex
的action
中
vuex的 module是什么?
面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex
的store
对象分割成模块(modules
)。
7、 Vue子组件调用父组件的方法
答案:
- 第一种方法是直接在子组件中通过
this.$parent.event
来调用父组件的方法 - 第二种方法是在子组件里用
$emit
向父组件触发一个事件,父组件监听这个事件就行了。
8、Webpack的四个核心概念有哪些?
答案:
- Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。
- Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
- Plugin:扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。
- Output:输出结果,在 Webpack 经过一系列处理并得出最终想要的代码后输出结果。
9、组件通信一般分为几种情况?
答案:
- 父子组件通信
- 兄弟组件通信
- 跨多层级组件通信
10、vue.js的两个核心是什么?
答案:
1、数据驱动,也叫双向数据绑定。
Vue.js数据观测原理在技术实现上,利用的是Object.defineProperty和存储器属性: getter和setter(所以只兼容IE9及以上版本),可称为基于依赖收集的观测机制。核心是VM,即ViewModel,保证数据和视图的一致性。
2、组件系统。
.vue组件的核心选项:
1、模板(template):模板声明了数据和最终展现给用户的DOM之间的映射关系。 2、初始数据(data):一个组件的初始数据状态。对于可复用的组件来说,这通常是私有的状态。 3、接受的外部参数(props):组件之间通过参数来进行数据的传递和共享。 4、方法(methods):对数据的改动操作一般都在组件的方法内进行。 5、生命周期钩子函数(lifecycle hooks):一个组件会触发多个生命周期钩子函数,最新2.0版本对于生命周期函数名称改动很大。 6、私有资源(assets):Vue.js当中将用户自定义的指令、过滤器、组件等统称为资源。一个组件可以声明自己的私有资源。私有资源只有该组件和它的子组件可以调用。 等等。
11、vue-router路由的两种模式?
答案:
vue-router路由提供了两种路由模式:hash模式和history模式。
hash模式:
vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
history模式:
如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。
//设置mode属性,设置路由模式
const router = new VueRouter({
mode: 'history',
routes: [...]
})
不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://itcgq.com/user/id 就会返回 404,这就不好看了。
所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
12、vue等单页面应用及其优缺点
答案:
优点:
无刷新体验,提升了用户体验; 前端开发不再以页面为单位,更多地采用组件化的思想,代码结构和组织方式更加规范化,便于修改和调整; API 共享,同一套后端程序代码不用修改就可以用于Web界面、手机、平板等多种客户端 用户体验好、快,内容的改变不需要重新加载整个页面。
缺点:
不支持低版本的浏览器,最低只支持到IE9; 不利于SEO的优化(如果要支持SEO,建议通过服务端来进行渲染组件); 第一次加载首页耗时相对长一些,出现白屏; 不可以使用浏览器的导航按钮需要自行实现前进、后退。
13、对于MVVM的理解?
答案:
VVM是Model-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。
- Model: 代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。我们可以把Model称为数据层,因为它仅仅关注数据本身,不关心任何行为
- View: 用户操作界面。当ViewModel对Model进行更新的时候,会通过数据绑定更新到View
- ViewModel: 业务逻辑层,View需要什么数据,ViewModel要提供这个数据;View有某些操作,ViewModel就要响应这些操作
MVVM主要解决了 MVC中大量的 DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。和当 Model 频繁发生变化,开发者需要主动更新到 View 。
13、Vue中双向数据绑定是如何实现的?
答案:
vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变; 核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法。
14、vue中如何实现tab栏切换功能?
答案:
遇到此问题,一定要先回答前两种方式,再提使用第三方UI库实现
在 vue 中,实现 Tab 切换主要有三种方式:
1、使用 component 动态组件实现 Tab切换 [推荐移动端使用]
2、使用 vue-router 路由配合<router-view></router-view>
标签实现
3、使用第三方插件
详解:
1、使用 component 动态组件实现 Tab切换:
动态组件 component: 渲染一个“元组件”为动态组件。依 isShow的属性值,来决定哪个组件被渲染。
示例:
<template>
<div>
<tab>
<tab-item selected @on-item-click="onItemClick">Tab标签一</tab-item>
<tab-item @on-item-click="onItemClick">Tab标签二</tab-item>
<tab-item @on-item-click="onItemClick">Tab标签三</tab-item>
</tab>
<component :isShow="currentView"></component>
</div>
</template>
<script type="text/javascript">
import { Tab, TabItem } from 'vux'
import initOne from '@/components/example/initOne.vue';
import initTwo from '@/components/example/initTwo.vue';
import initThree from '@/components/example/initThree.vue';
export default{
data () {
return {
currentView:"",
}
},
components : {
Tab,
TabItem,
initOne,
initTwo,
initThree
},
mounted(){
this.currentView = "initOne";
},
methods : {
onItemClick (index) {
if(index==0){
//Tab切换一
this.currentView = "initOne";
}
if(index==1){
//Tab切换二
this.currentView = "initTwo";
}
if(index==2){
//Tab切换三
this.currentView = "initThree";
}
}
}
}
</script>
2、通过 <router-view></router-view>
标签 和 vue-router
子路由 配合实现Tab切换
示例:
适合vue做后台管理系统时,做侧边栏功能
account.vue文件:
<template>
<div id="account">
<p class="tab">
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/account/course">我的课程</router-link>
<!-- 注意这里的路径,course和order是account的子路由 -->
<router-link to="/account/order">我的订单</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
</template>
在src/router/index.js:
import account from '../page/demo/account.vue'
import course from '../page/demo/course.vue'
import order from '../page/demo/order.vue'
export default new Router({
//路由配置
routes: [
{
path: '/account',
name: 'account',
component: Account,
children: [
{name: 'course', path: 'course', component: course},
{name: 'order', path: 'order', component: order}
]
}
]
})
15、构建的 vue-cli 工程都到了哪些技术,它们的作用分别是什么?
答案:
- vue.js:vue-cli工程的核心,主要特点是 双向数据绑定 和 组件系统。
- vue-router:vue官方推荐使用的路由框架。
- vuex:专为 Vue.js 应用项目开发的状态管理器,主要用于维护vue组件间共用的一些 变量 和 方法。
- axios( 或者 fetch 、ajax ):用于发起 GET 、或 POST 等 http请求,基于 Promise 设计。
- webpack:模块加载和vue-cli工程打包器。
16、路由的跳转方式?
答案:
声明式(标签跳转)
<router-link :to="index">
编程式( js跳转)
router.push('index')
17、$route
和$router
的区别?
答案:
$route
是“路由信息对象”,包括path
,params
,hash
,query
,fullPath
,matched
,name
等路由信息参数。- 而
$router
是“路由实例”对象包括了路由的跳转方法,钩子函数等
18、vue首屏加载优化方案有哪些?
答案:
Vue-Router
路由懒加载(利用Webpack
的代码切割)- 使用
CDN
加速,将通用的库从vendor
进行抽离 - 服务端渲染
SSR
- 组件按需加载
Webpack
开启gzip
压缩
19、Vue2 的响应式原理?
Vue的响应式原理是通过Object.defineProperty
实现的,通过Object.defineProperty
绑定过的对象,会变成「响应式」化,也就是说改变这个对象的时候会触发get和set事件,进而触发一些视图更新。
Vue
响应式原理的核心就是Observer
、Dep
、Watcher
。
image-20220323174244887
实现Vue2 的响应式原理的大致步骤如下:
(1)、侦测数据的变化(哪些数据发生了变化)【数据劫持+依赖收集和通知】
Observer
负责将数据转换成getter/setter形式,进行数据的劫持(监听数据的变化),Vue2 通过设定对象属性的 setter/getter 方法来监听数据的变化,getter 的时候会收集依赖,setter 的时候会触发依赖更新,在数据变更的时候通知Dep
更新视图。
Observer
的作用是:
- 负责把data对象中的属性转换成响应式数据(将数据转换成getter/setter形式),进行数据的劫持(监听数据的变化);
- 当数据发生变化时发送通知
Observer
类中的结构说明:
image-20220324220334084
(2)、收集视图依赖了哪些数据(变化的数据依赖了哪些数据)【发布者】
当数据的属性发生变化时,需要通知那些依赖该数据的地方,那由谁来通知呢?就是通过**Dep
,**Dep
就是帮我们收集依赖的数据,然后要通知到哪里,(比如:模板中使用了price 数据,当它发生变化时,要向使用了它的地方发送通知。)
Dep
负责管理数据的依赖列表;是一个发布订阅模式,上游对接Observer
,下游对接Watcher
。
Dep
的作用是:
- 收集依赖,添加观察者(
Watcher
) - 通知所有观察者
Dep
类中的结构说明:
image-20220324212356763
(3)、当数据变化时,自动“通知”需要更新的视图部分,并进行更新【观察者】
Watcher
是实际上的数据依赖,负责将数据的变化转发到外界(渲染、回调);
Watcher
的作用是:
- 当数据发生变化,通知依赖,
Dep
通过notify
方法通知所有的Watcher
实例更新视图 - 自身实例化的时候,往
Dep
中通过addSub
方法添加自己。
Watcher
类中的结构说明:
image-20220324221558981
一句话概括Vue2 的响应式原理:
首先将data
传入Observer
转成getter/setter
形式,变成响应式数据;当Watcher
实例读取数据时,会触发getter
,被收集到Dep
仓库中;当数据更新时,触发setter
,通知Dep
仓库中的所有Watcher
实例更新,Watcher
实例负责通知外界
20、Object.defineProperty
是ES5 还是 ES6 ?有几个参数?这几个参数的作用是什么?
是ES5,有三个参数,语法:Object.defineProperty(obj, prop, descriptor)
参数的作用:
obj
在对象上添加属性(一个添加属性的对象)- 定义或修改的属性的名称(是一个字符串式的属性名称)
- 定义或修改的属性描述符(是一个对象,可以修改一个对象的现有属性)
属性描述符是一个对象,有以下几种属性:
image-20220324215451849
21、defineProperty 和 proxy 的区别?
image-20220329104625229
22、组件传值的方式有哪些?
23、插槽及业务场景?
什么是插槽?
在vue中,引入的子组件标签中间是不允许写内容的。为了解决这个问题,官方引入了插槽(slot)的概念。
插槽,其实就相当于占位符。它在组件中给你的HTML模板占了一个位置,让你来传入一些东西。插槽又分为匿名插槽、具名插槽以及作用域插槽。
为什么我要给子组件中传入HTML,而不直接写在子组件中呢?答案是这样的。你可以想象一个场景,你有五个页面,这五个页面中只有一个区域的内容不一样,你会怎么去写这五个页面呢?复制粘贴是一种办法,但在vue中,插槽(slot)是更好的做法。
image-20220329101601043
匿名插槽,我们又可以叫它单个插槽或者默认插槽。与具名插槽相对,它不需要设置name属性。(它隐藏的name属性为default。)
<slot></slot>
**具名插槽 **与匿名插槽相对,加了name属性的匿名插槽就是具名插槽
<slot name='left'></slot>
作用域插槽其实就是可以传递数据的插槽。子组件中的一些数据想在父组件中使用,必须通过规定的方法来传递。在官方文档中提出了一条规则,父级模板里的所有内容都是在父级作用域中编译的。子模板里的所有内容都是在子作用域中编译的。如果你在父组件直接使用子组件中的值,是会报错的。
24、Vue2生命周期钩子有哪些?发起网络请求在哪个钩子里面?
初始化阶段 beforeCreate() created() beforeMount() Mounted() 更新阶段 bebforeUpdate() updated() 销毁阶段 beforeDestroy() destoryed() 不常用到的 activated() deactivated() errorCaptured
发起网络请求
一般来说我们会将数据请求放在mounted 阶段,如果放在created阶段那么SSR(Server-side Rendering)会在后端执行一次,在前端也执行一次,这并不符合我们的预期,放在updated里面因为更新太频繁了,我们不能每更新一次就请求一次数据,放在destoryed里面因为这个实例马上就要销毁了,请求了也没有多大的意义,所以最好我们就是放在 mounted 里面。
25、mounted 和 created 有什么区别?
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
26、$nexttick的作用和应用场景?
由于vue的响应式,并不是数据发生变化后立即更新DOM,而是更新DOM 属于异步执行操作,需等待所有的同步任务执行完成之后,才会进行异步任务执行。
作用
就是用来告知DOM什么时候更新完,当DOM更新完毕后,nextTick方法里面的回调就会执行。
应用场景
需要在视图更新之后,基于新的视图进行操作。
应用场景-实例
有一个div,默认用 v-if 将它隐藏,点击一个按钮后,改变 v-if 的值,让它显示出来,同时拿到这个div的文本内容。如果v-if的值是 false,直接去获取div内容是获取不到的,因为此时div还没有被创建出来,那么应该在点击按钮后,改变v-if的值为 true,div才会被创建,此时再去获取。
<div id="app">
<div id="div" v-if="showDiv">这是一段文本</div>
<button @click="getText">获取div内容</button>
</div>
<script>
var app = new Vue({
el : "#app",
data:{
showDiv : false
},
methods:{
/*
getText:function(){
this.showDiv = true;
var text = document.getElementById('div').innnerHTML;
console.log(text);
}*/
getText:function(){
this.showDiv = true;
this.$nextTick(function(){
var text = document.getElementById('div').innnerHTML;
console.log(text);
});
}
}
})
</script>
27、301 和 302 有什么区别?
301是永久重定向,而302是临时重定向。 当然,他们之间也是有共同点的,就是用户都可以看到url替换为了一个新的,然后发出请求。
301比较常用的场景是使用域名跳转,比如:我们访问 http://http://www.baidu.com 会跳转到 https://http://www.baidu.com,发送请求之后,就会返回301状态码,然后返回一个location,提示新的地址,浏览器就会拿着这个新的地址去访问。
301请求是可以缓存的, 即通过看status code,可以发现后面写着from cache。
302用来做临时跳转,比如未登陆的用户访问用户中心重定向到登录页面,访问404页面会重新定向到首页。
28、Sass和Less的区别?
编译环境不一样
Sass
的安装需要Ruby环境,是在服务端处理的。 Less
是需要引入less.js来处理Less代码输出css到浏览器,也可以在开发环节使用Less
,然后编译成css文件,直接放到项目中。
变量符不一样
SASS
变量符是 $
Less
变量符是 @
支持语句不同
Sass
支持条件语句,可以使用if{}else{},for{}循环、函数等等。
Less
不支持。
输出设置不同
Sass
提供4中输出选项:nested, compact, compressed 和 expanded。
输出样式的风格可以有四种选择,默认为nested
nested:嵌套缩进的css代码 expanded:展开的多行css代码 compact:简洁格式的css代码 compressed:压缩后的css代码
Less
没有输出设置
29、Mobx和Redux的共同点和区别?
共同点:
- 两者都是为了解决状态不好管理,无法有效同步的问题而产生的工具。
- 都是用来统一管理应用状态的工具
- 某一个状态只有一个可靠的数据来源
- 操作更新的方式是统一的,并且是可控的
- 都支持store与react组件
区别:
- redux将数据保存在单一的store中,而mobx将数据保存在分散的多个store中;
- redux使用plain object保存数据,需要手动处理变化后的操作,mobx使用observable保存数据,数据变化后自动处理响应的操作
- redux使用的是不可变状态,意味着状态只是只读的,不能直接去修改它,而是应该返回一个新的状态,同时使用纯函数;mobx中的状态是可变的,可以直接对其进行修改。
- mobx相对来说比较简单,在其中有很多的抽象,mobx使用的更多的是面向对象的思维,redux会比较复杂,因为其中的函数式编程思想掌握起来不是那么容易,同时需要借助一系列的中间件来处理异步和副作用。
- mobx中有更多的抽象和封装,所以调试起来会更加复杂,同时结果也更难以预测,而redux提供可以进行时间回溯的开发工具,同时其纯函数以及更少的抽象,让调试变得更加容易。
30、对于(React)副作用的理解?
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
Effect Hook 可以让你在函数组件中执行副作用操作,
useState
就是一个 Hook 。通过在函数组件里调用它来给组件添加一些内部 state。React 会在重复渲染时保留这个 state。useState
会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。
useEffect
就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
具有相同的用途,只不过被合并成了一个 API。
简而言之:useEffect 提供了 state 发生改变,以及组件卸载等“事项”的副作用。
副作用的应用无疑给前端编码带来了便利,因为利用它可以帮助我们完成数据驱动视图的理念,在大部分情况下避免了繁琐的 DOM 操作。在如今这个前端框架盛行的时代,副作用在前端的日常编码下可以说是无时无刻都存在的,它扮演者双刃剑的角色,不论是作为框架的设计者以及使用者,都应该 确保副作用是清晰的可追溯的,才能让我们的代码处于可控。
31、useEffect第二个参数不同,分别对应着哪些生命周期钩子?
useEffect这个钩子函数是用来模拟生命周期函数的。调用这个函数的时候他的第一个参数必须是一个函数,每一次render之后执行副作用和清除上一次副作用,该函数的返回值就是清除函数。第二个参数可以不传,也可以传递一个数组。
第二个参数不传,代表监听所有的属性更新,可以模拟componentDidUpdate
useEffect(()=>{console.log('任意属性该改变')})
第二个参数为一个空数组,可以模拟componentDidMount
useEffect(()=>{console.log('第一次渲染时调用')},[])
返回值是函数可以模仿模拟componentWillUnmount
useEffect(()=>{
const timer = setTimeout(()=>{
...
},1000)
return()=>{
console.log('组件销毁')
clearTimerout(timer)
}
})