一、HTML
1、行内元素有哪些?块级元素有哪些?空元素有哪些?
- 行内元素:span、 a、 b、 i、 img、 input、 select、 strong
- 块级元素:div、 p 、h1-h6、 table、 form、 ul、 ol、 lo、 dl、 dt、 dd
- 空元素:br、 hr、 img、 input、 link、 meta
2、src、href的区别
-
src
- 用于替换当前元素
- src是source的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求src资源时会将其指向的资源下载并应用到文档内,例如js脚本,img图片和frame等元素
- 当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等元素也如此,类似于将所指向资源嵌入当前标签内。这也是为什么将js脚本放在底部而不是头部
-
href
- 用于在当前文档和引用资源之间确立联系
- href是Hypertext Reference的缩写,指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接
- 并行下载资源并且不会停止对当前文档的处理。这也是为什么建议使用link方式来加载css,而不是使用@import方式
3、link、@import的区别
- link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS
- link引用CSS时,在页面载入时同时加载;@import需要页面完全载入以后加载
- link无兼容问题;@import是在CSS2.1提出的,低版本浏览器不支持
- link支持使用JavaScript控制DOM去改变样式;@import不支持
二、CSS
1、box 盒子模型
当对一个文档进行布局(layout)的时候,浏览器的渲染引擎会根据标准之一的 CSS 基础框盒模型,将所有元素表示为一个个矩形的盒子。
一个盒子由四个部分组成:
- content,内容
- border,边框
- padding,内边距,取值不能为负,受盒子的background属性影响
- margin,外边距
默认情况下,盒子模型为W3C 标准盒子模型
W3C 标准盒子模型
- 盒子总宽度 = width + padding + border + margin;
width/height 只是内容宽高,不包含 padding 和 border 值
IE 怪异盒子模型
- 盒子总宽度 = width + margin;
width/height 包含了 padding 和 border 值
box-sizing: content-box|border-box|inherit;
// W3C标准 | IE怪异 | 继承父元素
2、语义化标签
以前布局用div做,对于搜索引擎来说,是没有语义的,语义化标签旨在让标签有自己的含义
-
优点
- 页面很好地呈现内容结构、代码结构(代码结构清晰,方便阅读,有利于团队合作开发)
- 有利于SEO,搜索引擎优化
-
语义化标签
- title 文档标题
- h1 ~ h6 分级标题
- header 页眉通常包括网站标志、主导航、全站链接以及搜索框
- nav 标记导航,仅对文档中重要的链接群使用
- article 定义外部的内容,其中的内容独立于文档的其余部分。
- p 段落
- section 定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。
- aside 定义其所处内容之外的内容。如侧栏、文章的一组链接、广告、友情链接、相关产品列表等。
- footer 页脚,只有当父级是body时,才是整个页面的页脚。
3、position
- static正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效
- relative 相对定位元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。position:relative 对 table-*-group, table-row, table-column, table-cell, table-caption 元素无效
- absolute 绝对定位元素会被移出正常文档流,并不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margin),且不会与其他边距合并
- fixed 固定定位元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。fixed属性会创建新的层叠上下文。当元素祖先的transform,perspective或filter属性非none` 时,容器由视口改为该祖先
- sticky 粘性定位元素根据正常文档流进行定位,然后相对它的最近滚动祖先和最近块级祖先,包括table-related元素,进行偏移。偏移值不会影响任何其他元素的位置
4、center 水平垂直居中
-
水平垂直居中方法
-
不知道子元素宽高大小仍能实现水平垂直居中的方法有:
-
利用定位 + margin: auto
- 父元素relative、宽高;
- 子元素absolute、margin: auto
-
利用定位 + transform
- 父元素relative、宽高;
- 子元素absolute、宽高、 transform: translate(-50%,-50%);
-
利用定位 + margin: 负值
- 父元素relative、宽高;
- 子元素absolute、top: 50%、left: 50%、宽高、margin: 负值
-
flex布局
- 父元素flex、justify-content: center、align-items: center、宽高
-
grid布局
- 父元素:display: grid、justify-content: center、align-items: center、宽高
-
-
知道子元素宽高大小实现水平垂直居中的方法有:
-
table布局
- 父元素:display: table-cell、vertical-align: middle、 text-align: center、宽高
- 子元素:display: inline-block、宽高
-
-
-
内联和块级元素居中方法
-
内联元素居中布局
-
水平居中
- 行内元素可设置:text-align: center
- flex布局设置父元素:display: flex; justify-content: center
-
垂直居中
- 单行文本父元素确认高度:height === line-height
- 多行文本父元素确认高度:disaply: table-cell; vertical-align: middle
-
-
块级元素居中布局
-
水平居中
- 定宽: margin: 0 auto
- 绝对定位+left:50%+margin:负自身一半
-
垂直居中
- position: absolute设置left、top、margin-left、margin-top (定高)
- display: table-cell
- transform: translate(x, y)
- flex (不定高,不定宽)
- grid (不定高,不定宽),兼容性相对比较差
-
-
5、选择器
-
!important 最高
-
内联选择器 优先级1000
-
id选择器 优先级100
-
类和伪类选择器 优先级10
- :hover 鼠标悬停
- :visited 访问过
- :first-child 第一个孩子
- :checked 选中
-
元素选择器 优先级1
-
通配符选择器 优先级0
- 通配符使用星号*表示,意思是“所有的”
6、em_px_rem_vh_vw
传统的项目开发中,我们只会用到px、%、em这几个单位,它可以适用于大部分的项目开发,且拥有比较良好的兼容性。
从CSS3开始,浏览器对计量单位的支持又提升到了另外一个境界,新增了rem、vh、vw、vm等一些新的计量单位
px:绝对单位,页面按精确像素展示
em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算,整个页面内1em不是一个固定的值
rem:相对单位,可理解为root em, 相对根节点html的字体大小来计算
vh、vw:主要用于页面视口大小布局,在页面布局上更加方便简单
7、BFC
-
BFC(Block Formatting Context),块级格式化上下文,它是页面中的一块渲染区域,并且有一套属于自己的渲染规则:
- 内部的盒子会在垂直方向上一个接一个的放置
- 对于同一个BFC的俩个相邻的盒子的margin会发生重叠,与方向无关。
- 每个元素的左外边距与包含块的左边界相接触(从左到右),即使浮动元素也是如此
- BFC的区域不会与float的元素区域重叠
- 计算BFC的高度时,浮动子元素也参与计算
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然
- BFC目的是形成一个相对于外界完全独立的空间,让内部的子元素不会影响到外部的元素
-
触发BFC的条件包含不限于:
- 根元素,即HTML元素
- 浮动元素:float值为left、right
- overflow值不为 visible,为 auto、scroll、hidden
- display的值为inline-block、inltable-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid
- position的值为absolute或fixed
-
应用场景:
- 防止margin重叠(塌陷)
- 清除内部浮动
- 自适应多栏布局
8、sass_less_stylus
-
css预处理语言
- 扩充了 Css 语言,增加了诸如变量、混合(mixin)、函数等功能,让 Css 更易维护、方便
- 本质上,预处理是Css的超集
- 包含一套自定义的语法及一个解析器,根据这些语法定义自己的样式规则,这些规则最终会通过解析器,编译生成对应的 Css 文件
基本使用
// less和scss
.box {
display: block;
}
// sass和stylus
.box
display: block
嵌套
三者的嵌套语法都是一致的,甚至连引用父级选择器的标记 & 也相同
区别只是 Sass 和 Stylus 可以用没有大括号的方式书写
// less
.a {
&.b {
color: red;
}
}
变量
变量无疑为 Css 增加了一种有效的复用方式,减少了原来在 Css 中无法避免的重复「硬编码」
- less声明的变量必须以@开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号:分隔开
@red: #c00;
strong {
color: @red;
}
- sass声明的变量使用$开头
$red: #c00;
strong {
color: $red;
}
- stylus声明的变量没有任何的限定,可以使用$开头,不建议使用@符号开头声明变量。结尾的分号;可有可无,但变量与变量值之间需要使用=
red = #c00
strong
color: red
作用域
Css 预编译器把变量赋予作用域,也就是存在生命周期。就像 js 一样,它会先从局部作用域查找变量,依次向上级作用域查找
- sass中不存在全局变量
- less与stylus的作用域跟javascript十分的相似,首先会查找局部定义的变量,如果没有找到,会像冒泡一样,一级一级往下查找,直到根为止
混入
Mixins可以将一部分样式抽出,作为单独定义的模块,被很多选择器重复使用。可以在Mixins中定义变量或者默认参数
- 在less中,混合的用法是指将定义好的ClassA中引入另一个已经定义的Class,也能使用够传递参数,参数变量为@声明
- Sass声明mixins时需要使用@mixinn,后面紧跟mixin的名,也可以设置参数,参数名为变量$声明的形式
- stylus中的混合和前两款Css预处理器语言的混合略有不同,他可以不使用任何符号,就是直接声明Mixins名,然后在定义参数和默认值之间用等号(=)来连接
代码模块化
模块化就是将Css代码分成一个个模块。scss、less、stylus三者的使用方法都如下所示
@import './common';
@import './github-markdown';
@import './mixin';
@import './variables';
9、css3动画
-
是什么CSS动画(CSS Animations)是为层叠样式表建议的允许可扩展标记语言(XML)元素使用CSS的动画的模块即指元素从一种样式逐渐过渡为另一种样式的过程常见的动画效果有很多,如平移、旋转、缩放等等,复杂动画则是多个简单动画的组合
-
css实现动画的方式,有如下几种:
- transition 实现渐变动画
- transform 转变动画
- animation 实现自定义动画
transition 实现渐变动画
- property:填写需要变化的css属性
- duration:完成过渡效果需要的时间单位(s或者ms)
- timing-function:完成效果的速度曲线
- delay:动画效果的延迟触发时间
注意:并不是所有的属性都能使用过渡的,如display:none<->display:block
transform 转变动画
包含四个常用的功能:
- translate:位移
- scale:缩放
- rotate:旋转
- skew:倾斜
一般配合transition过度使用
注意的是,transform不支持inline元素,使用前把它变成block
animation 实现自定义动画
CSS 动画只需要定义一些关键的帧,而其余的帧,浏览器会根据计时函数插值计算出来,
通过 @keyframes 来定义关键帧,旋转一周例子:
/* 方式一 */
@keyframes rotate{
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* 方式二 */
@keyframes rotate{
0% { transform: rotate(0deg); }
50% { transform: rotate(180deg); }
100% { transform: rotate(360deg); }
}
/* 应用 */
animation: rotate 2s;
10、浮动元素
- 如果有多个浮动元素,浮动元素会按顺序排下来而不会发送重叠的现象
- 浮动元素会尽可能向顶端对齐、向左或向右对齐
- 如果有非浮动元素和浮动元素同时存在,并且非浮动元素在前,则浮动元素不会高于非浮动元素
- 行内元素与浮动元素发送重叠,边框、背景、内容都会显示在浮动元素之上
- 块级元素与浮动元素发送重叠,边框、背景会显示在浮动元素之下,内容会显示在浮动元素之上
11、flex布局
web应⽤有不同设备尺⼨和分辨率,这时需要响应式界⾯设计来满⾜复杂的布局需求。
Flex弹性盒模型的优势在于开发⼈员只是声明布局应该具有的⾏为,⽽不需要给出具体的实现⽅式,浏览器负责完成实际布局,当布局涉及到不定宽度,分布对⻬的场景时,就要优先考虑弹性盒布局。
- order: 定义子元素的排列顺序。数值越小,排列越靠前,默认为0
- flex-grow: 定义子元素的放大比例,默认为0,即如果存在剩余空间,也不放大
- flex-shrink:定义了子元素的缩小比例,默认为1,即如果空间不足,该项目将缩小
- flex-basis:定义了在分配多余空间之前,子元素占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即子元素的本来大小
12、有哪些⽅式可以隐藏⻚⾯元素?
- opacity: 0 本质上是将元素的透明度将为0,就看起来隐藏了,但是依然占据空间且可以交互
- visibility: hidden 与上⼀个⽅法类似的效果,占据空间,但是不可以交互了
- overflow: hidden 这个只隐藏元素溢出的部分,但是占据空间且不可交互
- display: none 这个是彻底隐藏了元素,元素从⽂档流中消失,既不占据空间也不交互,也不影响布局
- z-index: -9999 原理是将层级放到底部,这样就被覆盖了,看起来隐藏了
- transform: scale(0,0) 平⾯变换,将元素缩放为0,但是依然占据空间,但不可交互
13、你对css sprites的理解,好处是什么?
-
雪碧图也叫CSS精灵, 是⼀CSS图像合成技术,开发⼈员往往将⼩图标合并在⼀起之后的图⽚称作雪碧图
-
background-image、background-position和background-size属性
-
优点:
- 减少加载多张图⽚的 HTTP 请求数(⼀张雪碧图只需要⼀个请求)
- 提前加载资源
-
缺点:
- CSS Sprite维护成本较⾼,如果⻚⾯背景有少许改动,⼀般就要改这张合并的图⽚
三、JavaScript
1、js数据类型
-
基本数据类型(值类型)
-
七种基本数据类型
- String 字符串
- Number 数值
- Boolean 布尔
- Null 空
- Undefined 未定义
- Symbol (ES6) ES6 引入的一种新的原始数据类型,表示独一无二的值
- BigInt (ES10) ES10 引入
-
保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在栈空间,通过按值访问
-
-
复杂数据类型(引用类型)
-
三种引用类型
- Object 对象
- Array 数组
- Function 函数
-
保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,按址访问,JavaScript不允许直接访问堆内存中的位置,因此操作对象时,实际操作对象的引用
-
2、array_api 数组方法
增 :
下面前三种是对原数组产生影响的增添方法,第四种则不会对原数组产生影响
- push() 将一个或多个元素添加到数组的末尾,并返回该数组的新长度
- unshift() 在数组开头添加任意多个值,然后返回新的数组长度
- splice() 传入三个参数,分别是开始位置、0(要删除的元素数量)、插入的元素,返回空数组
- concat() 用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组
删:
下面三种都会影响原数组,最后一项不影响原数组:
- pop() 从数组中删除最后一个元素,并返回该元素的值
- shift() 从数组中删除第一个元素,并返回该元素的值
- splice() 传入两个参数,分别是开始位置,删除元素的数量,返回包含删除元素的数组
- slice() 返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变
改:
- splice() 传入三个参数,分别是开始位置,要删除元素的数量,要插入的任意多个元素,返回删除元素的数组,对原数组产生影响
查:
- indexOf() 返回数组中给定元素的第一个索引位置,如果不存在,则返回-1
- includes() 判断一个数组是否包含一个指定的值,包含返回 true,否则返回false
- find() 返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
const array = [5, 12, 8, 130, 44];
const found = array.find(element => element > 10); console.log(found); // 12
const unfound = array.find(element => element > 150); console.log(unfound); // undefined
排序方法:
- reverse() 将数组中元素的位置颠倒,并返回该数组
- sort() 对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的
转字符串:
- join() 接收一个参数,即字符串分隔符,返回包含所有项的字符串
迭代方法:
- some()
对数组每一项都运行传入的函数,如果有一项函数返回 true ,则这个方法返回 true
- every()
对数组每一项都运行传入的函数,如果对每一项函数都返回 true ,则这个方法返回 true
- forEach()
对数组每一项都运行传入的函数,没有返回值
- filter()
对数组每一项都运行传入的函数,函数返回 true 的项会组成数组之后返回 (返回符合条件的项,不计算)
- map()
对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组(返回每一项计算后的结果)
- 数组去重方法
- ES6 Set
let array = [1, 2, 1, 1, '1'];
function unique(array) {
return Array.from(new Set(array));
}
console.log(unique(array)); // [1, 2, "1"]
- filter + indexOf
function unique(arr) {
return arr.filter(function(item, index, arr) {
return arr.indexOf(item, 0) === index;
});
}
-
filter + sort
-
for + splice
-
reduce + includes
function unique(arr){
return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
- hasOwnProperty
function unique(arr) {
var obj = {};
return arr.filter(function(item, index, arr){
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
3、原型、原型链
-
原型
- 所有引用类型都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
- 所有函数都有一个prototype(原型)属性,属性值是一个普通的对象
- 所有引用类型的__proto__属性指向它构造函数的prototype
-
原型链
- 当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的proto隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,一直往上层查找,直到null还没有找到,则返回undefined这样一层一层向上查找就会形成一个链式结构,我们称为原型链
- Object.prototype.proto === null
- 所有从原型或更高级原型中的得到、执行的方法,其中的this在执行时,指向当前这个触发事件执行的对象
let a = [1,2,3];
a.__proto__ === Array.prototype; // true
4、ajax、axios 区别
-
ajax
-
什么是ajax
- AJAX 全称Async Javascript and XML,即异步的 JavaScript 和 XML,用于快速创建动态页面,实现无刷新更新数据
- 是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页
- Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面
-
实现 Ajax 异步交互需要服务器逻辑进行配合,需要完成以下步骤:
- 创建 Ajax 的核心对象 XMLHttpRequest 对象
- 通过 XMLHttpRequest 对象的 open() 方法与服务端建立连接
- 构建请求所需的数据内容,并通过 XMLHttpRequest 对象的 send() 方法发送给服务器端
- 通过 XMLHttpRequest 对象提供的 onreadystatechange 事件监听服务器端你的通信状态
- 接受并处理服务端向客户端响应的数据结果
- 将处理结果更新到 HTML 页面中
-
ajax({
type: 'post', // 请求类型
dataType: 'json', // 数据类型
data: {}, // 数据
url: 'https://xxxx', // 请求路径
success: function(text,xml){ //请求成功后的回调函数
console.log(text)
},
fail: function(status){ //请求失败后的回调函数
console.log(status)
}
})
-
优点:
- 无刷新更新数据
- 异步与服务器通信
- 前后端负载平衡
- 界面与应用分离
-
缺点:
- ajax不能使用back和history功能,即对浏览器的破坏
- 安全问题,ajax暴露了与服务器交互的细节
- 对搜索引擎的支持比较弱
- 破坏程序的异常处理机制
- 违背URL和资源定位的初衷
- 不能很好的支持移动设备
- 针对MVC的编程,不符合MVVM浪潮
- 回调地狱问题,多个请求之间如果有先后关系,就会出现回调地狱
-
适用:
- 表单驱动的交互
- 深层次的树的导航
- 对数据进行过滤和操纵相关数据的场景
- 类似投票、yes/no等无关痛痒的场景
-
不适用:
- 简单的表单
- 搜索
- 基本的导航
- 替换大量的文本
- 对呈现的操纵
-
axios
-
基于Promise的HTTP库,可以用在浏览器和node.js中
-
特性:
- 自动转换成JSON数据格式
- 客户端支持防御XSRF/CSRF跨站请求伪造
- 支持Promise api
- 在浏览器中创建XMLHttpRequests
-
-
区别
- axios是通过Promise实现对ajax技术的一种封装
- axios实现了对ajax的封装
- axios是ajax、ajax不止axios
5、copy 拷贝
浅拷贝
- 浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝
- 如果属性是基本类型,拷贝的就是基本类型的值
- 如果属性是引用类型,拷贝的就是内存地址
- 只复制属性指向某个对象的指针,而不复制对象本身,共享内存地址,修改对象属性会影响原对象
在JavaScript中,存在浅拷贝的现象有:
- Object.assign(target, …sources) 将所有可枚举属性的值从一个或多个源对象分配到目标对象。返回目标对象
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target); // { a: 1, b: 4, c: 5 }
console.log(returnedTarget); // { a: 1, b: 4, c: 5 }
- Array.prototype.slice()
- Array.prototype.concat()
- 使用拓展运算符(…)实现的复制
const fxArr = ["One", "Two", "Three"]
const fxArrs = [...fxArr]
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]
深拷贝
深拷贝开辟一个新的栈,两个对象属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
常见的深拷贝方式有:
- _.cloneDeep()
- jQuery.extend() 将一个或多个对象的内容合并到目标对象
- JSON.stringify() 将一个 JavaScript 对象或值转换为 JSON 字符串
- 手写循环递归
6、使用 JSON.Stringify 深拷贝的缺陷
-
使用JSON.stringify序列化之后的数据,再JSON.parse会丢失部分数据
-
注意事项:
- 使用JSON.Stringify 转换的数据中,如果包含 function,undefined,Symbol,这几种类型,不可枚举属性, JSON.Stringify序列化后,这个键值对会消失
- 转换的数据中包含 NaN,Infinity 值,JSON序列化后的结果会是null
- 转换的数据中包含Date对象,JSON.Stringify序列化之后,会变成字符串
- 转换的数据包含RegExp 引用类型序列化之后会变成空对象
- 无法序列化不可枚举属性
- 无法序列化对象的循环引用。例如: obj[key] = obj
- 无法序列化对象的原型链
7、js节流、防抖
-
节流
- 将多次执行变为每隔一段时间执行
- 当持续触发事件时,保证在一定时间内只调用一次事件处理函数
- 应用场景:防止用户连续频繁的点击事件
- 例子:提交按钮、王者荣耀技能释放的cd
-
防抖
- 将多次执行变为最后一次执行
- 在事件被处罚n秒后再执行回调,如果在这n秒内又被触发,则重新计时
- 应用场景:用户在输入框中连续输入一串字符后,只会在输入完成后去执行最后一次查询的ajax请求
- 例子:王者荣耀回城
8、js闭包
- 能够读取其他函数内部变量的函数
- 定义在一个函数内部的函数
- 本质上,闭包是将函数内部和函数外部连接起来的桥梁
- 使用闭包主要原因:返回可以返回其他函数的函数
9、箭头函数与普通函数的区别?
- 箭头函数没有prototype(原型),所以箭头函数本身没有this
- 箭头函数的this在定义的时候继承自外层第一个普通函数的this
- 如果箭头函数外层没有普通函数,严格模式和非严格模式下它的this都会指向window(全局对象)
- 箭头函数本身的this指向不能改变,但可以修改它要继承的对象的this
- 箭头函数的this指向全局,使用arguments会报未声明的错误
- 箭头函数的this指向普通函数时,它的argumens继承于该普通函数
- 使用new调用箭头函数会报错,因为箭头函数没有constructor
- 箭头函数不支持new.target
- 箭头函数不支持重命名函数参数,普通函数的函数参数支持重命名
- 箭头函数相对于普通函数语法更简洁优雅
10、如何实现一个new
-
在《JavaScript模式》这本书中,new一个构造器:
- 创建一个空对象,将它的引用赋给this,继承函数的原型
- 通过this将属性和方法添加至这个对象
- 最后返回this指向的新对象
-
new过程会新建对象,此对象会继承构造器的原型与原型上的属性,最后它会被作为实例返回
// ES5构造函数
let Parent = function (name, age) {
//1.创建一个新对象,赋予this,这一步是隐性的,
// let this = {};
//2.给this指向的对象赋予构造属性
this.name = name;
this.age = age;
//3.如果没有手动返回对象,则默认返回this指向的这个对象,也是隐性的
// return this;
};
const child = new Parent();
11、call和apply的区别是什么?哪个性能更好?
- 相同:call和apply都是function原型上的方法,用于改变this指向的
- 区别:传入参数的形式不一样,call是一个一个传参,而apply把所有参数用数组形式传参
- 性能:call比apply性能要好一些
- bind与他们类似(传参数也是一个个传参),都是改变this指向,只是预先处理函数,但是并不会立即执行
let arr = [10,20,30]
let obj = {}
function fn(x,y,z){}
fn.call(obj,...arr) //基于ES6的展开运算符,可以展开依次传递给函数
fn.apply(obj,arr) //x,y,z分别为10 20 30
12、js中的Error
-
错误类型
- Error:所有错误的父类型
- ReferenceError:引用的变量不存在
- TypeError:数据类型错误
- RangeError:数据值不在其所允许的范围内
- SyntaxError:语法错误
-
错误处理
- 捕获错误:try . . . catch
- 抛出错误:throw error
-
错误对象
- message属性:错误相关信息
- stack属性:函数调用栈记录信息
13、let、const、var
-
var
- 变量
- 存在变量提升,允许重复声明变量
- 变量可以在声明之前调用,值为undefined
-
let
- 变量
- 不存在变量提升,不允许重复声明变量
- 块级作用域,存在暂时性死区
- 先声明后使用,否则报ReferenceError错
-
const
- 常量
- 块级作用域
- 不允许重复声明
14、Promise
-
Promise的理解和使用
-
抽象表达
- Promise是JS中进行异步编程的新的解决方案
-
具体表达
- 从语法上来说:Promise是一个构造函数
- 从功能上来说:Promise对象用来封装一个异步操作并可以获取其结果
-
promise的状态改变(只有2种,只能改变一次)
- pending变为resolved
- pending变为rejected
-
promise基本流程
- 构建Promise对象时,需要传入一个executor函数,主要业务流程都在executor函数中执行.
- Promise构造函数执行时立即调用executor函数,resolve和reject两个函数作为参数传递给executor,resolve和reject函数被调用时,分别将promise的状态改为fulfilled(完成)或者rejected(失败).一旦状态改变,就不会再变,如何时候都可以得到这个结果.
- 在executor函数中调用resolve函数后,会触发promise.then设置的回调函数,而调用reject函数后,会触发promise.catch设置的回调函数.
-
为什么要用promise
- 指定回调函数的方式更加灵活:可以再请求发出甚至结束后指定回调函数
- 支持链式调用,可以解决回调地狱问题
-
15、Promise构造函数是同步执行还是异步执行,then方法呢?
- Promise构造函数是同步执行的
- then方法是异步执行的
new Promise(function(resolve,reject){})
// 例如
new Promise(resolve=>{
console.log(1);
resolve(3);
}).then(num=>{
console.log(num);
});
console.log(2); // 123
16、Async/Await如何通过同步的方式实现异步?
-
概括
- async/await 是 Generator 的语法糖,就是一个自执行的generate函数。利用generate函数的特性把异步的代码写成“同步”的形式
-
说明
- 首先,js 是单线程的,所谓单线程,就是:执行代码是一行一行的往下走(即所谓的同步),如果上面的没执行完,那就只能等着实现异步的核心就是回调钩子,那就是 callback之前的函数嵌套,大量的回调函数,使代码阅读起来晦涩难懂,不直观,形象的称之为回调地狱(callback hell)
- 为力求在写法上简洁明了,可读性强,es6+陆续出现了 Promise、Generator、Async/Await
- async/await 是参照 Generator 封装的一套异步处理方案,可以理解为 Generator 的语法糖而 Generator 又依赖于迭代器 Iterator,而 Iterator 的思想又来源于单向链表终于找到源头了:单向链表
17、promise与async/await
-
什么是async/await
- async/await是写异步代码的新方式,以前的方法有回调函数和Promise
- async/await是基于Promise实现的,它不能用于普通的回调函数
- async/await与Promise一样,是非阻塞的
- async/await使得异步代码看起来像同步代码,这正是它的魔力所在
- await关键字只能用在aync定义的函数内。
- async函数会隐式地返回一个promise,该promise的reosolve值就是函数return的值
-
为什么async/await 比promise好
-
代码简洁
- 使用async函数可以让代码简洁很多,不需要像Promise一样需要些then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码
-
错误捕获。Async/Await 让 try/catch 可以同时处理同步和异步错误
- promise示例中,try/catch 不能处理 JSON.parse 的错误
- 使用aync/await的话,catch能处理JSON.parse错误
-
中间值
- 场景:调用promise1,使用promise1返回的结果去调用promise2,然后使用两者的结果去调用promise3
-
const makeRequest = () => {
return promise1().then(value1 => {
return Promise.all([value1, promise2(value1)])
}).then(([value1, value2]) => {
return promise3(value1, value2)
})
}
- 使用async/await通过同步的方式实现异步,代码会变得异常简单和直观
const makeRequest = async () => {
const value1 = await promise1()
const value2 = await promise2(value1)
return promise3(value1, value2)
}
-
错误栈
- 如果 Promise 连续调用,对于错误的处理是很麻烦的。你无法知道错误出在哪里
- async/await中的错误栈会指向错误所在的函数
-
调试
- async/await能够使得代码调试更简单。两个理由使得调试Promise变得非常痛苦:
- 《1》不能在返回表达式的箭头函数中设置断点
《2》如果你在.then代码块中设置断点,使用Step Over快捷键,调试器不会跳到下一个.then,因为它只会跳过异步代码。 - 使用await/async时,你不再需要那么多箭头函数,这样你就可以像调试同步代码一样跳过await语句。
18、cookie、sessionStorage、localStorage
关于cookie、sessionStorage、localStorage三者的区别主要如下:
- 存储大小: cookie数据大小不能超过4k,sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
- 有效时间:localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据; sessionStorage 数据在当前浏览器窗口关闭后自动删除;cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
- 数据与服务器之间的交互方式, cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端; sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
应用场景:
- 标记用户与跟踪用户行为的情况,推荐使用cookie
- 适合长期保存在本地的数据(令牌),推荐使用localStorage
- 敏感账号一次性登录,推荐使用sessionStorage
- 存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用indexedDB
四、HTTP
1、get、post
- 数据传输⽅式不同:GET请求通过URL传输数据,⽽POST的数据通过请求体传输。
- 安全性不同:POST的数据因为在请求主体内,所以有⼀定的安全性保证,⽽GET的数据在URL中,通过历史记录,缓存很容易查到数据信息。
- 数据类型不同:GET只允许 ASCII 字符,⽽POST⽆限制
- GET⽆害: 刷新、后退等浏览器操作GET请求是⽆害的,POST可能重复提交表单
- 特性不同:GET是安全(这⾥的安全是指只读特性,就是使⽤这个⽅法不会引起服务器状态变化)且幂等(幂等的概念是指同⼀个请求⽅法执⾏多次和仅执⾏⼀次的效果完全相同),⽽POST是⾮安全⾮幂等
2、状态码
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
---|---|
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
- 200 - 请求成功
- 301 - 永久移动。资源(网页等)被永久转移到其它URL
- 302 - 临时移动。客户端应继续使用原有URL
- 304 - 未修改。所请求的资源未修改,服务器不会返回任何资源
- 305 - 使用代理。所请求的资源必须通过代理访问
- 403 - 服务器理解请求客户端的请求,但是拒绝执行此请求
- 404 - 请求的资源(网页等)不存在
- 500 - 内部服务器错误
- 501 - 服务器不支持请求的功能,无法完成请求
- 502 - 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
- 504 - 充当网关或代理的服务器,未及时从远端服务器获取请求
- 505 - 服务器不支持请求的HTTP协议的版本,无法完成处理
3、从输入网址到浏览器呈现页面内容,中间发生了什么?
-
网络通信
-
互联网内各网络设备间的通信都遵循TCP/IP协议,利用TCP/IP协议族进行网络通信时,会通过分层顺序与对方进行通信
-
分层由高到低分别为:应用层(HTTP客户端)、传输层(TCP)、网络层(IP)、数据链路层(网络)
-
发送端从应用层往下走,接收端从数据链路层网上走
-
步骤:
- 应用层DNS解析域名
- 应用层客户端发送HTTP请求
- 传输层TCP传输报文
- 网络层IP协议查询MAC地址
- 数据到达数据链路层
- 服务器接收数据
- 服务器响应请求
- 服务器返回相应文件
-
-
页面渲染
- 现代浏览器渲染页面的过程是这样的:解析HTML以构建DOM树 –> 构建渲染树 –> 布局渲染树 –> 绘制渲染树。
- DOM树是由HTML文件中的标签排列组成,渲染树是在DOM树中加入CSS或HTML中的style样式而形成。渲染树只包含需要显示在页面中的DOM元素,像display属性值为none的元素都不在渲染树中。
- 在浏览器还没接收到完整的HTML文件时,它就开始渲染页面了,在遇到外部链入的脚本标签或样式标签或图片时,会再次发送HTTP请求重复上述的步骤。在收到CSS文件后会对已经渲染的页面重新渲染,加入它们应有的样式,图片文件加载完立刻显示在相应位置。在这一过程中可能会触发页面的重绘或重排。
4、强缓存、协商缓存的区别
-
强缓存
- 直接从本地副本比对读取,不去请求服务器,放回状态码200
- 服务端请求头中配置cache-control,常见的设置是max-age public private no-cache no-store等,其中,max-age 缓存时间,单位s
-
协商缓存
- 请求资源时,把用户本地该资源的 etag 同时带到服务端,服务端和最新资源做对比
如果资源没更改,返回304,浏览器读取本地缓存
如果资源有更改,返回200,返回最新的资源 - 请求头配置 etag 内容编码唯一标识、last-modified 资源最后修改时间
- 请求资源时,把用户本地该资源的 etag 同时带到服务端,服务端和最新资源做对比
5、跨域
-
什么是跨域?
- 非同源请求 协议、域名、端口
- 当一个请求url的协议、端口、域名三者之间任意一个与当前页面url不同即为跨域
-
跨域是浏览器行为
-
非同源限制
- 无法读取非同源页的Cookie、LocalStorage、IndexDB
- 无法接触非同源页的DOM和JS对象
- 无法向非同源地址发送AJAX请求
-
跨域解决方案
-
jsonp
-
原理利用了script不受同源策略的限制 script引入外部js没有跨域限制
-
生命回调函数允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住json数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了
-
优点
- 兼容性比较好,IE支持,一些老的项目需要兼容IE
-
缺点
- 只支持get请求
- 某些浏览器url会有长度限制
- 不能上传文件或者一些比较复杂的请求
-
-
cors (Cross-Orign Resource Sharing 跨域资源共享)
-
原理它允许浏览器向跨源服务器发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制
-
浏览器支持目前所有浏览器都支持,IE10+
-
两种请求
-
简单请求
- get、post、head
- 服务端需设置 Access-Control-Allow-Origin
-
复杂请求
- put、delete、Content-Type: ‘application/json’
- 服务端需设置 Access-Control-Allow-Credentials 和 Access-Control-Expose-Headers
-
-
-
代理
- 把非同源请求变为同源请求
- 前端发请求给代理服务器,代理服务器再向后端服务器请求
- 缺点:需要额外的代理服务器
-
6、HTTPS握手过程
-
HTTPS(全称: Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的HTTP通道,简单讲是HTTP的安全版
- HTTP: 直接通过明文在浏览器和服务器之间传递信息
- HTTPS: 采用 对称加密 和 非对称加密 结合的方式来保护浏览器和服务端之间的通信安全
- 默认端口号:443
-
握手过程
- 客户端发起请求,以明文传输请求信息
- 服务端返回协商的信息结果,包括证书公钥
- 客户端验证证书的合法性,合法性验证通过之后,客户端生成一个随机值,并用证书公钥加密,发送给服务器
- 客户端将加密后的密钥发给服务端,服务端用密钥解密密钥,并用密钥加密要发送的内容
- 服务端将加密后的内容发送给服务端,用密钥解密信息
五、vue
1、列表组件中写key的作用
-
vue和react都是采用diff算法来对比新旧虚拟节点,从而更新节点。在vue的diff函数的交叉对比中,当新节点跟旧节点头尾交叉对比没有结果时,会根据新节点的key去对比旧节点数组中的key,从而找到相应旧节点
-
作用
-
避免就地复用的情况,更高效准确
- 当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染
- 只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出
-
利用key的唯一性生成map对象来获取对应节点,比遍历方式更快
-
2、vue生命周期及执行顺序
-
vue每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建、数据初始化、挂载、更新、销毁,这就是一个组件所谓的生命周期。
-
在组件中具体的方法有:
-
beforeCreate
- 表示实例在完全创建出来之前会执行它,在执行它时,data和methods中的数据都还未初始化
-
created
- 此时data和methods已经初始化完成,created()完成之后,vue开始编译模板,最终在内存中生成一个编译好的最终模板字符串,然后把模板字符串渲染为内存中的dom
-
beforeMount
- 表示模板在内存中已经编译好了,但是并没有渲染到页面中。页面显示的还仅仅是模板字符串
-
mounted
- 此时内存中的模板已经真实的挂载到了页面中,用户可以看到渲染好的页面了
-
beforeUpdate
- 运行中的事件,执行它时,data中的数据已经被更新了,但是页面中的data还未被替换过来
-
updated
- 运行中的事件,执行它时,页面和data中的数据已经同步了
-
beforeDestroy
- 实例销毁之前调用
-
destroyed
- 当我们离开这个页面的时候,便会调用这个函数
-
-
vue中内置的方法 属性和vue生命周期的运行顺序
- props 组件传值
- methods 方法
- data 数据
- computed 计算属性
- watch 侦听属性
3、vue底层原理(深入响应式原理、双向绑定)
- 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty把这些 property 全部转为 getter/setter
- 这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更
- 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染
- Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因
4、MVVM的理解
- MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自动传递给 View,即所谓的数据双向绑定。
- Vue.js 是一个提供了 MVVM 风格的双向数据绑定的 Javascript 库,专注于View 层。它的核心是 MVVM 中的 VM,也就是 ViewModel。 ViewModel负责连接 View 和 Model,保证视图和数据的一致性,这种轻量级的架构让前端开发更加高效、便捷
- 优点:
1、主要目的是分离视图(View)和模型(Model)
2、降低代码耦合,提高视图或者逻辑的重用性
3、提高了模块的可测试性
5、为什么前端要工程化,要是使用MVC?
相对 HTML4,HTML5 最大的亮点是它为移动设备提供了一些非常有用的功能,使得 HTML5 具备了开发App的能力, HTML5开发App 最大的好处就是跨平台、快速迭代和上线,节省人力成本和提高效率,因此很多企业开始对传统的App进行改造,逐渐用H5代替Native,到2015年的时候,市面上大多数App 或多或少嵌入都了H5 的页面。既然要用H5 来构建 App, 那View 层所做的事,就不仅仅是简单的数据展示了,它不仅要管理复杂的数据状态,还要处理移动设备上各种操作行为等等。因此,前端也需要工程化,也需要一个类似于MVC 的框架来管理这些复杂的逻辑,使开发更加高效。 但这里的 MVC 又稍微发了点变化:
View :UI布局,展示数据
Model :管理数据
Controller :响应用户操作,并将 Model 更新到 View 上
这种 MVC 架构模式对于简单的应用来看是OK 的,也符合软件架构的分层思想。 但实际上,随着H5 的不断发展,人们更希望使用H5 开发的应用能和Native 媲美,或者接近于原生App 的体验效果,于是前端应用的复杂程度已不同往日,今非昔比。这时前端开发就暴露出了三个痛点问题:
1、 开发者在代码中大量调用相同的 DOM API,处理繁琐 ,操作冗余,使得代码难以维护。
2、大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
3、 当 Model 频繁发生变化,开发者需要主动更新到View ;当用户的操作导致 Model 发生变化,开发者同样需要将变化的数据同步到Model 中,这样的工作不仅繁琐,而且很难维护复杂多变的数据状态。
其实,早期jquery 的出现就是为了前端能更简洁的操作DOM 而设计的,但它只解决了第一个问题,另外两个问题始终伴随着前端一直存在。
MVVM 的出现,完美解决了以上三个问题:
- MVVM 由 Model、View、ViewModel 三部分构成,Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。
- 在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
- ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理
6、组件传值
-
props 传值 (父传子)
- 子组件必须注册好要传的数据
-
$attrs 传值 (爷传孙)
- 使用的时候只需给父组件中的孙组件配置v-bind=“$attrs”,然后再爷组件中传入孙组件所需要的数据,孙组件正常接收即可
-
事件 传值 (子传父)
- 子组件使用 this.$emit() 方法传值给父组件,父组件接收数据并调用自定义事件
-
状态管理工具 Vuex
-
路由跳转传参
-
本地缓存 storage
7、v-if、v-show的区别
- 手段:v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样式属性控制显隐;
- 编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;
- 编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译; v-show是在任何条件下都被编译,然后被缓存,而且DOM元素保留;
- 性能消耗: v-if有更高的切换消耗;v-show有更高的初始渲染消耗;
- 使用场景: v-if适合运营条件不大可能改变;v-show适合频繁切换
8、Vue中computed和watch的区别
-
计算属性computed :
- 变量不在 data中定义,而是定义在computed中,有返回值。函数名直接在页面模板中渲染,不加小括号
- 根据传入的变量的变化,进行结果的更新
- 支持缓存,只有依赖数据发生改变,才会重新进行计算
- 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
- 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
-
侦听属性watch:
- 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作
- 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值
- 不支持缓存,数据变,直接会触发相应的操作
- 支持异步
- 当一个属性发生变化时,需要执行对应的操作;一对多
- 当有一些数据需要随着其它数据变动而变动时,或者当需要在数据变化时执行异步或开销较大的操作时,用 watch
9、Vuex
-
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
-
五个核心
-
State
- 单一状态树,存储数据
- 用一个对象就包含了全部的应用层级状态。作为一个唯一数据源而存在。这也意味着,每个应用将仅仅包含一个 store 实例
- 单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照
-
Getters
- getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
-
Mutations
- 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
- Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
-
Actions
- Action 提交的是 mutation,而不是直接变更状态
- Action 可以包含任意异步操作
-
Modules
- 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿
- 为了解决以上问题,Vuex 允许我们将 store 分割成模块
- 每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
-
-
优点
- js 原生的数据对象写法,,比起 localStorage 不需要做转换,使用方便
- 属于 vue 生态一环,能够触发响应式的渲染页面更新 (localStorage 就不会)
- 限定了一种可预测的方式改变数据,,避免大项目中,数据不小心的污染
- 减少了ajax请求次数,有些情景可以直接从内存中的state获取
-
缺点
- 刷新浏览器,Vuex中的state会重新变为初始状态,Vuex存储的值会丢失
-
缺点对应解决方案
- 使用插件:vuex-along 或 vuex-persistedstate
-
Vuex和本地存储的区别
-
注:很多同学觉得用localstorage可以代替vuex,,对于不变的数据确实可以,但是当两个组件共用一个数据源(对象或数组)时,如果其中一个组件改变了该数据源,希望另一个组件响应该变化时,localstorage,sessionstorage无法做到
-
vuex存储在内存,localstorage(本地存储)则以文件的方式存储在本地
-
vuex用于组件之间的传值,本地存储则主要用于不同页面之间的传值。
-
当刷新页面时vuex存储的值会丢失,sessionstorage页面关闭后就清除掉了,localstorage不会。
-
六、其他
1、webpack、gulp的区别?
- webpack是前端构建工具,又称前端模块化打包工具。它实现了模块化开发和文件处理,能够将各个模块进行按需加载,不会导致加载了无用或冗余的代码
- gulp可以进行js、html、css、img文件的压缩打包,是自动化构建工具,可以将多个js文件或是css压缩成一个文件,并且可以压缩为一行,以此来减少文件体积,加快请求速度,减少请求次数。并且gulp有task定义处理事务,从而构建整体流程,它是基于流的自动化构建工具
2、同步、异步的区别
-
同步
- 阻塞模式
- 执行某个请求的时候,直到收到返回信息才继续执行下去。提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事
- 普通B/S模式、打电话
-
异步
- 非阻塞模式
- 不需要一直等下去,而是继续执行下面的操作。请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
- AJAX技术、发消息
3、ES6代码转ES5代码的实现思路是什么?
-
谈到es6代码转es5代码肯定想到的是babel,那么babel是如何实现转码的呢?
-
三个步骤
- 解析(parse): 解析代码字符串,生成AST(抽象语法树)
- 转换(transform):按一定的规则转换,修改AST
- 生成(generate):将修改后的AST生成新的普通代码
4、TCP三次握手和四次挥手
-
三次握手
- 首先A向B发出连接请求报文段
- B收到请求后,向A发送确认
- A收到B的确认后,还要向B给出确认
-
为什么需要三次握手过程
- 为了防止已失效的连接请求报文段突然又传送到了B,因而产生错误
-
四次挥手
- 客户端 A 的 TCP 进程先向服务端发出连接释放报文段,并停止发送数据,主动关闭 TCP 连接
- B收到连接释放报文段后即发出确认释放连接的报文段
- A收到B的确认后,进入FIN—WAIT(终止等待2)状态,等待B发出连接释放报文段,如果B已经没有要向A发送的数据了,其应用进程就通知TCP释放连接
- A收到B的连接释放请求后,必须对此发出确认
-
为什么需要四次挥手
- 为了保证A发送的最后一个ACK报文段能够到达B
- 防止”已失效的连接请求报文段”出现在连接中
5、重绘、回流
-
回流
- 渲染树因为元素的尺寸,布局,隐藏等改变而需要重新对其进行构建的操作(影响布局)
- 每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候是一定会发生回流的,因为要构建render tree
-
重绘
- 当渲染树中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的(不影响布局)
-
关联:回流一定是重绘,重绘不一定是回流
-
如何减少重绘和回流?
- 想要改变元素样式,通过改变元素的 class 名 (尽可能在 DOM 树的最末端改变class)
- 避免设置多项内联样式,因为每个都会造成回流,样式应该合并在一个外部类,这样当该元素的class属性可被操控时仅会产生一个reflow
- 在操作offset 、scroll、client、width、height等属性时,先用变量先进行存储,在进行操作
6、微前端
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
微前端架构具备以下几个核心价值:
- 技术栈无关
主框架不限制接入应用的技术栈,微应用具备完全自主权 - 独立开发、独立部署
微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新 - 增量升级在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
- 独立运行
每个微应用之间状态隔离,运行时状态不共享
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见
7、小程序api
-
路由
- wx.switchTab() 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
- wx.reLaunch() 关闭所有页面,打开到应用内的某个页面
- wx.redirectTo() 关闭当前页面,跳转到应用内的某个页面。不能跳到 tabbar 页面
- wx.navigateTo() 保留当前页面,跳转到应用内的某个页面。不能跳到 tabbar 页面
- wx.navigateBack() 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages获取当前的页面栈,决定需要返回几层
-
交互
- wx.showToast() 显示消息提示框
- wx.showModal() 显示模态对话框
- wx.showLoading() 显示 loading 提示框。需主动调用 wx.hideLoading 才能关闭提示框
-
网络
- wx.request() 发起 HTTPS 网络请求
- wx.downloadFile() 下载文件资源到本地
- wx.uploadFile() 将本地资源上传到服务器
8、前端性能优化
-
优化方案
-
减少HTTP请求数
- 雪碧图CSS Sprite
- 图片映射image maps 允许在单张图片上有很多带链接的图片
- Font icon 使用字体图标来代替图标
-
利用缓存机制
- 将JavaScript与CSS设置为外部文件引入而不是直接嵌入到HTML中
-
css样式放在头部引入
-
js脚本放在尾部引入
-
优化代码方案
- 避免css表达式
- 避免重定向
- 最小化操作DOM
- 压缩资源文件
-
优化网络请求
- CDN 内容分发网络
- DNS预解析
- 尽早释放缓冲
-
-
优点:
- 用户角度:让页面加载得更快,对用户的操作响应得更及时,能够给用户提供更为友好的体验
- 服务商角度:减少页面请求数,减小请求所占带宽,能够节省服务器资源