1.浏览器输入URL后发生了什么?
1:读取DNS缓存,如果DNS缓存中找到IP且在有效期内,就跳过查找IP步骤,直接访问该IP地址。
2:未找到IP,通过DNS将域名解析成IP。
3:TCP的3次握手
第一次握手:客户端发送syn包到服务器
第二次握手:服务器收到SYN包必须确认客户的SYN包,然后再发送给客户端SYN+ACK包
第三次握手:客户端收到SYN+ACK包,然后发送给服务器ACK包
完成三次握手,客户端与服务器开始连接数据。
4.发送http请求
5.服务器处理http请求,并返回http报文
6.浏览器解析渲染页面
7.断开连接,tcp的四次挥手
第一次挥手:客户端发送给服务器,请求报文发送完毕,准备关闭
第二次挥手:服务器发送给客户端,我接收完请求报文,准备关闭
第三次挥手:服务器发送给客户端,我响应报文发送完毕,准备关闭
第四次挥手:客户端发送给服务器,我响应报文接收完毕,准备关闭
2.重绘,重排,回流(同35)
⚠️ 网上的回流跟重排两种说法,其实都是一个意思。
⚠️ 回流/重排必定会引起重绘,但重绘不一定会引起回流/重排。回流/重绘会导致渲染树重新计算,开销比重绘大,所以尽量避免回流/重绘的产生。
1: 回流/重排的产生
1> 页面进行首次渲染时,所有组件都要进行首次布局,这是开销最大的一次回流/重排。
2> 浏览器窗口尺寸的改变
3> 元素位置和尺寸发生改变
4> 元素字体大小发生改变
5> 激活css伪类(比如: hover )
6> 设置style
2: 重绘的产生
不影响布局,只影响外观的属性,比如visibility、outline、背景色等属性的改变
常见的避免方法:
1> 样式集中改变,比如需要在js中改变某元素的宽高,可以用js给元素添加特定的clssName。
3.http
http1.0 请求方式: GET,POST,HEAD
http1.1 请求方式:OPTIONS,PUT,DELETE,TRACE,CONNECT
GET跟POST的区别:
1.数据传输方式不同:GET通过URL传输数据,POST通过请求体传输。
2.安全性不同:POST数据在请求体内,有一定的安全性,GET数据在URL中,通过历史记录缓存很容易就找到数据信息。
3.数据类型不同:GET传输是ASCII字符串,POST没有限制。
4.GET无害:刷新,后退等浏览器操作,GET请求是无害的,POST可能就要重复提交表单。
PUT与POST都是给服务器发送新增资源,有什么区别:
1.PUT方法是幂等的,就是一次跟多次执行的结果是一样的,无副作用,而POST是非幂等的。
2.通常情况下PUT指向一个具体的资源,而POST是指向的一个资源级。
⚠️ 「POST表示创建资源,PUT表示更新资源」这种说法是错误的,两个都能新增资源,区别在于幂等性
4.深拷贝和浅拷贝
1.关于js数据类型
基本类型:number, boolean, string, undefined, null, symbol
引用类型:object 如 array, function, object
2.深拷贝与浅拷贝的区别
假设b复制了a,如果修改b导致a的值也被修改,则为浅拷贝;如果修改b的值,a保持原有值不变,则是深拷 贝。
当a为引用类型时,b=a;其实b复制的是a的引用地址,而并非堆里面的值。
深拷贝是拷贝对象各个层级的属性。
3.怎样实现深拷贝
1.function objCopy = (obj) => {
const newObj = Object.Array(obj) ? [] : {};
if (obj && typeOf obj === 'object') {
for (let key from obj) {
if (Object.Array(obj[key])) {
newObj[key] = objCopy(obj[key])
} else {
newObj[key] = obj[key]
}
}
}
return newObj;
}
2.function objCopy = (obj) => {
const _obj = JSON.Stringify(obj);
return JSON.parse(_obj);
}
⚠️只能拷贝数组或对象,不能处理函数
3.lodash中的cloneDeep
4.浅拷贝实现方式
object.assign(), 扩展运算符
和原始数据是否指向同一对象 | 第一层数据为基本数据类型 | 原始数据中包含子对象 | |
赋值 | 是 | 改变会使原数据改变 | 改变会使原数据改变 |
浅拷贝 | 否 | 改变不会使原数据改变 | 改变会使原数据改变 |
深拷贝 | 否 | 改变不会使原数据改变 | 改变不会使原数据改变 |
5.原型与原型链
原型:原型分为隐式跟显示,每个对象都有一个隐式原型,它指向自己的构造函数的显示原型。
原型链: 多个_proto_组成的集合成为原型链
.所有实例的_proto_都指向他们构造函数的prototype
.所有的prototype都是对象,自然它的_proto_指向Object的prototype
.所有的构造函数的隐式原型指向的都是Function()的显示原型
.object的隐式原型是null
6.js中什么是数据类型,什么是引用类型,具体是怎么储存的。
基本数据类型:
number,string,boolean, undefined, null, symbol
引用数据类型:
object,array,date,function,regExp
存储方式:
基本数据类型是存储在栈中,引用数据类型存储在堆中,栈中存储的是引用链接,注意堆内存不会自动释放,使用完对象需要手动将对象设置为null
7.闭包
闭包:
有权访问另一个函数作用域中的变量,常见方式:函数内部嵌套另一个函数,内部函数可以访问外部函数的变量。
原理:
外部函数调用时,会创建自己的作用域链,当执行完毕时,作用域链会被销毁,但内部函数还在引用这个活动对象,内部函数会将外部函数的活动对象添加到自己的作用域链中,直到内部函数执行完毕时,活动对象才会被销毁。
优点:
防止变量污染,内部函数可以调用外部函数
缺点:
占内存,使用不当容易引起内存泄漏
8.react与vue的区别
9.浏览器缓存机制
10.数组去重
1. 利用forEach循环数组,通过includes或indexOf判断是否在新数组,不在则插入新数组
function unique (arr) {
const result = [arr[0]];
arr.forEach(item => {
if (!result.includes(item)) {
result.push(item)
}
});
return result;
}
2.利用Set结构不会有重复元素的原理,以及...运算符
function unique (arr) {
return [...new Set(arr)];
}
3.利用Set结构不会有重复元素的原理,以及Array.from方法
function unique (arr) {
return [Array.from(new Set(arr))];
}
4.利用sort排序,将重复的放在一起,然后使用splice删除重复元素
function unique (arr) {
arr.sort((a,b) => a-b);
for (let i = 0; i< arr.length; i++) {
if (arr[i] == arr[i+1]) {
arr.splice(i, 1);
i--;
}
}
return arr;
}
11.react刷新的几种方式
1.setState
2.外界props发生改变(redux数据改变)
3.强制更新 this.forceUpdete()
⚠️正确用法:<button onClick={() => this.forceUpdate()}
错误写法: <button onClick={this.forceUpdate}>错误写法</button>
12.非递归优化
13.promise
promise是异步编程的一种解决方案,比传统的回调函数更加合理和更加强大。promise是使用链式操作,降低了编码难度,代码可读性明显增强。
promise有三种状态pending(进行中), rejected(已失败), fulfilled(已成功);
特点:
1.对象的状态不受外界的干扰,只有异步操作结果可以决定当前是哪个状态。
2.状态只会从pending--fulfilled或者pending--rejected;
3.状态一旦改变就不会再变
promise对象是一个构造函数,用来生成promise实例;promise构造函数接收一个函数作为参数,函数有两个参数(参数作用改变promise对象的状态),分别是resolve(进行中-成功),reject(进行中-失败);
promise 构造出来的实例有以下方法
1. then (实例状态发生改变时的回调函数,第一个参数是resolved状态的回调,第二个参数是rejected状态的回调函数。then方法返回的是一个新的promise实例)
2. catch (捕获错误,发生错误时的回调函数)
3. finally(不管promise最后状态如何,都会执行)
4. all(用于将多个promise实例包装成一个新的promise实例)
如: const p = Promise.all([p1,p2,p3]);(p1,p2,p3应为promise实例)
p的状态分为两种:
1⃣️:p1,p2,p3状态都为fulfilled,则p的状态为fulfilled,此时p1,p2,p3返回值组成一个数组,传递给p的回调函数;
2⃣️:若p1,p2,p3中有一个的状态为rejected,则p的状态为rejected,此时第一个被rejected的实例的返回值会传递给p的回调函数;
5. race(将多个promise实例包装成一个新的promise实例。率先改变promise实例状态的返回值则传递给p的回调函数)
promise与async await的区别
1.promise通过catch来捕获错误, async await 是通过try catch 或者then方法来捕获错误
2.await关键字只能在async定义的函数内,await后面跟promise对象。
3.promise后面跟多个then方法,假如第一个then报错,后面的then不会执行,直接返回,直到catch方法
⚠️async await使用then方法捕获错误
window.onload=async () => {
let res = await getData(3).then((res) => [null, res]).catch(err => [err,null])
}
14.map ,forEach, for, for in , for of ,filter, reduce的区别
1.for...in 遍历数组索引,对象的属性。使用fo...in遍历时,原型链上所有属性都会被访问。
解决方法: 可以使用hasOwnProperty()来判断一个属性是否存在于实例中。
如:const arr = ['a', 'b','c']
arr.prototype.test = ['e', 'f'];
for (let i in arr) {
if (arr.haOwnProperty(i)){
console.log(arr[i]);
}
}
// a,b,c
2.forEach 遍历数组,但是不能使用break,continue,return 语句
3.for 遍历数组
4.for of 遍历数组(数组中的value),也可以遍历字符串,支持Map和Set对象的遍历,可以正确响应break,continue,return。不能遍历一个普通对象,会报错。
5.map 遍历数组,有返回值,可以返回一个结果数组,遍历对象的话会报错,map只能循环数组或者对象数组。
6.filter: 过滤,当返回值为true时,才会返回当前处理的元素
7.reduce:接收一个函数作为累加器,数组中的每个值(从左到右开始缩减,最终计算为一个值)
注:reduce对空数组不会执行回调函数,可用于数组去重,降维
15.如何优化首屏加载
16.判断数据类型的方法
1.typeof
eg: typeof ‘a’ === 'string' //true
⚠️ typeof null === 'object' //true 无法分辨是null还是object
2.instanceof
eg: new Number(1) instanceof Number //true
⚠️ : 123 instanceof Number // false 只能判断对象是否存在与目标对象的原型链中
3.contructor
eg: console.log([123].contructor.name) //Array
⚠️: null,undefined 没有contractor属性
4.object.prototype.toString.call()
延伸题:
1.instanceof原理
function myInstanceof (L,R) {
var RP = R.prototype;
var LP = L._proto_;
while(true) {
if (LP === null) {
return false
}
if (RP === LP) {
return true;
}
LP = LP._proto_;
}
}
2.为什么typeof null 为object?
因为在js中,对象的储存都是使用二进制,如果二进制前三位都是0 ,系统会判定为object类型,而null的二进制的前三位都是0.
17.手写call,apply, bind
实现思路:
call跟apply:
.判断是否是函数调用,若非函数调用抛异常
.通过新对象(context)来调用函数
.给context创建一个fn设置为需要调用的函数
.结束调用完之后删除fn
bind实现思路:
.判断是否是函数调用,若非函数调用抛异常
.返回函数
.判断函数的调用方式,是否是被new出来的
.new出来的话返回空对象,但是实例的__proto__指向_this的prototype
.完成函数柯里化 Array.prototype.slice.call()
1.手写call
Function.prototype.MyCall = (context){
if (typeof this !== 'function') {
throw new typeError('not a function');
}
context = context || window;
context.fn = this;
let args = Array.from(arguments),slice(1);
let resule = context.fn(...args);
delete context.fn;
return result;
}
2.手写apply
Function.prototype.MyApply = (context) {
if (typeof this !== 'function) {
throw new TypeError('not a function');
}
context = context || window;
context.fn = this;
let result;
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
resule = context.fn();
}
delete context.fn;
return result;
}
3.手写bind
Function.prototype.MyBind = (context) {
if (typeof this !== 'function') {
throw new TypeError('not a function');
}
const _this = this;
const args = Array.prototype.slice.call(arguments, 1);
return function F () {
//判断是不是new出来的
if (this instanceof F) {
return new _this(...args, ...argyments);
} else {
return _this.apply(context, args.concat(...arguments));
}
}
}
18.手写数组降维
1. function flatten (arr) {
return [].concat(...arr.map(item => Array.isArray(item) ? flatten(item) : item))
}
2.function arrFn (arr) {
const newArr = [];
const loopFn = (arr) {
arr.forEach(item => {
if (Array.isArray(item)) {
loopFn(item);
} else {
newArr.push(item)
}
})
}
looFn(arr);
return newArr;
}
3.
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
//使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity);
// [1, 2, 3, 4, 5, 6]
19.虚拟dom?
虚拟dom是一个js对象,通过对象的形式展示dom结构。
虚拟dom保存了真实dom的层次关系和一些基本属性,与真实的dom一一对应。
如果只更新虚拟dom,页面是不会重绘的。
优点: 保证性能下限
无需手动操作dom
跨平台
缺点:无法进行极致优化
虽然虚拟dom+合理的优化,足以应对绝大部分的性能需求,但是有一些性能要求极高的应用中,虚拟dom无法进行针对性的极致优化。
首次渲染大量dom时,由于多了一层虚拟dom的计算会比innerhtml插入慢
20.什么是MVVM?
MVVM是前端的架构模式,作用是为了让前端业务逻辑与html代码更加分离。它把每个页面分成了M(model数据模型),V(view 视图),VM(viewModel 视图模型);其中VM是M和V的调度者,M和V不直接关联,通过中间的VM,VM提供了双向绑定功能,V和M中其中一方改变,另一方也会随之改变。
21.flex布局
1.flex-direction 主轴方向 row columns row-reverse columns-reverse
2.flex-wrap 是否换行 nowarp wrap wrap-reverse
3.flex-flow 1,2属性的简写
4.justify-context 主轴上的对齐方式 flex-start flex-end space-between center
5.align-items 交叉轴上的对齐方式。flex-start flex-end stretch center
6.align-content 多根轴线的对齐方式
22.原型怎么实现继承
原型实现继承?
1.构造函数继承
写法:构造函数名字.call(当前对象, 属性, 属性, 属性。。。)
function Person(name, age, sex, weight) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function () {
console.log("您好");
};
function Student(name,age) {
//借用构造函数
Person.call(this, name, age, sex, weight);
this.score = score;
}
var stu1 = new Student("小明",10);
console.log(stu1.name, stu1.age);//输出 小明 10
var stu2 = new Student("小红",20,"女","20kg","120");
console.log(stu2.name, stu2.age);//输出 小红 20
2.原型方法实现
写法:通过改变子类的原型(prototype)指向,指向父类即可。
3.组合继承
组合继承是 原型方法实现继承和借用构造函数实现继承的结合
4.拷贝继承
拷贝继承是把一个对象中的属性或者方法直接复制到另一个对象中。
23.react-ssr
1.什么是ssr?
在服务端渲染框架中所创建的虚拟dom
2.为什么要实现服务端渲染?
增加首屏加载速度,解决白屏问题,可以直接渲染页面,利于seo(搜索引擎)优化
24.js本地缓存方式
1.cookie
cookie中存储的数据,如果没有设置有效期的话,浏览器关闭就会被清空。
一般同源是4kb。
浏览器与服务器之间来回传递。
所有同源窗口都是共享的。
2.localStorage
需要手动清除,否则会一直存在。
只能存储字符串。
大小5MB。
尽在本地
所有同源窗口都有共享
3.sessionStorage
窗口关闭,信息就会丢失。
大小5MB。
仅在本地。
不在不同的浏览器窗口共享,即使是同一页面。
25.react-router的路由有几种模式?
1.browseRouter: 浏览器的路由方式,也就是开发中的最常用的方式。
2.hashRouter: 在路径前加入#号成为一个Hash值,Hash模式好处是,再也不会因为我们刷新页面而找不到我们对应的路径。
3.memoryRouter: 不存储history,所有路由过程保存内存里,不能进行前进后退,因为地址栏没有发生变化
4.nativeRouter: 经常配合ReactNative 使用,多用于移动端。
5.staticRouter: 设置静态页面路由,需要在后台服务器配合设置,比如设置服务端渲染时使用。
26.js中常用的设计模式
1.工厂模式✳️
2.单例模式✳️
3. 原型模式
4.适配器模式
5.代理模式
6.策略模式
7.迭代器模式
8.发布-订阅模式 ✳️
9.命令模式
10.状态模式
27.css权重如何计算?
1: !import 不推荐使用;
2: 内联样式。权重值为1000;
3: ID选择器。 权重为100;
3: 类名,属性选择器,伪类。 权重为10;
4: 标签, 伪元素。权重值为1;
其它: 通配符, 子选择器 , 相邻选择器 如: *, >, + 权值为0
28: DOCTYPE的作用?
作用是告诉浏览器以哪种模式去解析html文档。
有两种模式:标准模式(<!DOCTYPE html>)与怪异模式
标准模式:以浏览器最高标准呈现
怪异模式: 页面以比较宽松向后兼容来显示
29.一些常用的meta标签有哪些?
<!-- 关键字,搜所引擎 SEO -->
<meta http-equiv="keywords" content="关键字1,关键字2,...">
<meta name='author' content='开源技术团队' />//网页作者
<meta name='viewport' content='width=device-width,initical-scale=1.0,maxnum-scale=1.0,use-scale=no' /> //移动端常用视口
<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1' /> //使用浏览器版本
<!-- 页面描述 -->
<meta http-equiv="description" content="网页描述">
<!-- 清除缓存(再访问这个网站要重新下载!) -->
<meta http-equiv="cache-control" content="no-cache, must-revalidate">
<!-- 不缓存 -->
<meta http-equiv="cache-control" content="no-cache" />
30.display: none与visibility:hidden 的区别?
display: none:
1.非继承属性, 子节点会随着父节点消失,改变子节点属性也不会显示
2. 隐藏后的元素无法点击,占据的空间消失
visibility: hidden:
1.继承属性,子节点通过设置visibility: visible 可以显示
2.隐藏元素所占据的空间还保留
31.null与undefined的区别?
null:表示控对象,转为数值为0
undefined:表示缺少值 ,转为数值为NaN
1:变量声明,没有赋值,默认为undefined
2:调用函数,应该提供的参数没有提供,默认为undefined
3:对象没有赋值的属性,默认值为undefined
4:函数没有返回值
32.什么叫栅格化?
将网页一行等比例划分,比如一行划分为12等份,然后在每个格子中开发,这就是栅格化
33.React.child.map 与map的区别?
React.child.map: 可以处理未知数据类型,即使是undefined与null,此方法将返回null或undefined
map: 只能处理数组,不是数组会报错
34.作用域与作用域链?
1⃣️:作用域分为: 全局作用域,函数作用域,块级作用域
1: 全局作用域
全局作用域是指在最外层函数内外定义的变量拥有全局作用域,或者直接赋值的变量会自定声明为全局作用域,所有window对象的属性都拥有全局作用域
2:函数作用域
在函数内部声明的变量
3:块级作用域
使用es6新增的let或const声明可以声明块级作用域,可以在函数中创建也可以在代码块中创建(由{}包裹的代码片段)。
let跟const声明的变量不会进行变量提升,也不可以重复声明。
2⃣️:作用域链?
在当前作用域中查找所需变量,但是当前作用域没有该变量,就会去父级作用域查找,依次向上级作用域查找,直到访问到window对象就被终止,这一层层关系就是作用域链。
35:回流与重绘(同2)
回流: 当render tree中的一部分(或全部),因为元素的尺寸,布局,隐藏等改变,而需要重新构建。
重绘: 当render tree中一些元素需要更新属性,而这些属性只影响外观,不影响布局,则称为重绘。
回流:
添加或删除可见的dom元素
元素位置改变
元素尺寸改变(margin, padding, width, height, border)
内容的改变(文本改变,或者图片大小改变)
页面渲染初始化
浏览器窗口尺寸改变(resize事件发生)
重绘:
元素的属性或样式发生变化
(color, background-color, border-radius, border-shadow)
如何减少回流跟重绘?
css:
使用transform来代替top
避免使用table布局
尽量避免多层嵌套,结构尽量扁平化。
使用visibility,opacity 代替display:none
js:
给dom设置css避免一行一行的设置(如:el.style.width = '40px', el.style.color = 'red')
涉及到批量修改dom时,使用先将dom元素的display设置为none,然后修改,最后将其重新展示
36.类数组与数组的区别
类数组是一个对象,有length属性,但是不能使用数组的方法。
常见的类数组有: 函数的arguments, DOM方法的返回结果
类数组转化为数组的方法:
[...arguments] (扩展运算符)
Array.from(arguments)
[].slice.call(arguments)
37.React.component 与React.pureComponent的区别?
pureComponent时一个纯组件,可以用来优化React程序,减少render执行次数。
pureComponent会自动执行shouldComponentUpdate。
pureComponent的shouldComponentUpdate进行的是浅比较,也就是说引用类型只会比较是否为同一地址。
38.受控组件与非受控组件
受控组件:是指在使用表单收集用户输入时,绑定onChange事件,状态发生改变就会触发onChange事件,更新组件的state。
非受控组件:表单的数据交由DOM节点来控制。
39.js获取url参数
1.返回需要的参数值
function getUrlvalue (type) {
var query = window.location.search.subString(1);
var params = query.split('&');
for (let i = 0; i< params.length; i++) {
const values = params[i].split('=');
if (values[0] == type) {
return values[1];
}
}
return false;
}
2.参数以对象的形式返回
function getUrlParams (url) {
let params = url.split('?');
let keyValue = params.split('&');
let obj = {};
for (let i = 0; i< keyValue.length; i++) {
let item = kayValue('=');
let key = item[0];
let value = item[1];
obj[key] = value;
}
return obj;
}
40.redux的工作流程
redux包含三要素: store, action , reducer
store: 就是数据保存的地方,可以把它看成一个容器,整个应用只有一个store。同时store还具有将action与reducer联系在一起的作用。
action: 就是一普通对象,其中type属性是必须的,用来表示action的名称,type一般定义为普通的字符串常量。
reducer: 本质上是一个函数,它接受当前的state和收到的action作为参数并返回一个新的state。
用户发出action,发出方式用到了dispatch。
然后store自动调用reducer,并传入两个参数,当前state与收到的action,reducer 会返回新的state。
state一旦变化,store就会自动调用监听函数,触发重渲染。
41.css超出隐藏
单行:
width: 300px;
overflow: hidden;//溢出隐藏
text-overflow: ellipsis;//溢出用省略号
white-space: noWrap; //段落中的文字不换行
多行:
width: 300px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;//弹性伸缩盒子模型
-webkit-box-orient: vertical;//伸缩盒子子元素从上到下垂直排列
-webkit-line-clamp: 3; //显示的行数
42.webpack中loader与plugin的区别
1.loader只专注于转化文件这一领域,完成压缩,打包,语言翻译
而plugin不仅只是局限在打包,资源的加载上,还可以打包优化和压缩重新定义环境变量。
2.loader运行在打包文件之前,plugin在整个编译周期都起作用。
43.css-loader与style-loader区别
css-loader: 找出css中的依赖,压缩资源。
style-loader: 通过一个js脚本创建一个style标签,然后将css-loader解析后的内容挂载到html
44.setState注意事项
1.不能直接设置this.state的值,需要使用setState;this.state不会触发render
2.调用setState后,可能不会立即生效。
3.在一些原生事件如:addEventListener,setTimeout,setInterval 事件中是可以取到最新值,
在react的生命周期与合成时间中是异步,不能取到最新的值
45. 函数声明与函数表达式的区别
函数声明的例子:
function name () {}可以在声明之前调用
函数表达式的例子: //不可以在表达式赋值完成前调用
var name = function () {}
var name = function test() {}
46.宏任务与微任务
微任务: 1.发起者 JS引擎 2.事件:promise等 3,运行:先运行
宏任务:
1.发起者:宿主(node, 浏览器)
2.事件:script(整体代码,setTimeout, setInterval)
3.后运行
先script整体代码执行,遇到宏任务放置宏任务队列,微任务放置微任务队列,
执行结束后,执行全部的微任务,当执行微任务时遇到微任务就放置微任务队列末尾,
依次执行,直至微任务队列清空。再执行下一个宏任务,这就是eventLoop
例子:
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
//1,7,6,8,2,4,3,5,9,11,10,12
47.隐式类型转换,显示类型转换
显示类型转换: Number, parseInt, parseFloat, Boolean(), String
隐式类型转换: 主要发生在+,-,*,/以及==,>,<这些运算符之间。
而这些运算符只能操作基本类型,在运算前,先将两边的值转换为基本数据类型。
1>: +运算符
1.两边有一个string,两边都被隐式转换为字符串
2.其它情况,两边都被转换为number
var a = '5';
console.log(+a+5) //10
console.log(a+5) // 55
console.log(+'5'+5) //10
2>: < 和 >比较符
如果两边都是字符,则比较顺序,其他情况,转化为数字再比较
3>: ==操作符
1.类型相同,直接比较两者是否相等
2.类型不同,看是否比较的是undefined与null,是直接返回true
3.两者类型是否为string与number,是的话将字符串转为number
4.一方为boolean,把boolean转换为number
5.一方为object,且另一方为string,number,symbol,则把object转换为原始类型
48.数组有哪些原始方法?
1.数组转化为字符串
toString, join
2.数组尾部操作方法
push: 尾部插入
pop: 尾部删除
3.数组首部操作方法
shift: 首部删除
unshift: 首部插入
4.数组连接
concat //返回拼接好的数组,不影响原数组
5.数组插入/删除方法
splice: splice(开始位置,删除个数,向数组添加的新值)
6.数组截取方法
slice: slice(start,end)
7.数组排序
sort:可以传入一个函数,传入前后两个值,如果返回为正数,则交换两个参数的位置,影响原数组
数字排序(数字和升序):
var points = [40,100,1,5,25,10];
points.sort(function(a,b){return a-b});
数字排序(数字和降序):
var points = [40,100,1,5,25,10];
points.sort(function(a,b){return b-a});
8.反转数组
reverse: 将改变原数组
49.前端浏览器的兼容问题
1.浏览器种类及内核
IE浏览器: Trident内核,也称为IE内核
Chrome浏览器: webkit内核,现在是Blink内核
Firefox浏览器:Firefox内核
safari浏览器: webkit内核
OperaL浏览器:最初Presto内核, 从webkit到Blink内核
360浏览器:IE+Chrome双内核
猎豹浏览器:IE+Chrome双内核
百度浏览器: IE+Chrome双内核
qq浏览器: Trident(兼容模式)+webkit(高速模式)
2.常见的兼容模式
不同浏览器的标签默认的margin和padding不同
图片默认有边距
边距重叠问题:两个或多个块级盒子的垂直相邻边距会重叠 (都为正值则取最大,一正一负则取两值相加,都是负值则取绝对值最大的那个值)
cursor: hand 显示手型,在Safari上不支持。统一使用cursor:pointer
事件绑定方式:
IE:dom.attachEvent
其他浏览器:dom.addEventListener
addEventListener的语法:
document.addEventListener(event, function, useCapture);
event: 事件名称的字符串
function: 事件发生后的需执行的操作
useCapture: 可选(布尔值)指定事件在捕获阶段执行还是冒泡阶段执行
true:捕获阶段 false: 冒泡阶段 (默认值)
阻止事件冒泡和事件捕获: event.stopPropagation();
3.浏览器css兼容前缀
-o-transform: rote(7deg) //opera
-moz-transform: rote(7deg) //Firefox
-ms-transform: rote(7deg) //IE
-webkit-transform: rote(7deg) //chrome
4.判断是否为IE浏览器
function isIE() {
if (!!window.ActiveXObject || 'ActiveXObject' in window) {
return true;
} else {
return false;
}
}
50.css3新特性
1.新增选择器: nth-child(n), first-child, last-child
2.弹性盒模型: display: flex;
3.媒体查询: @media
4.颜色透明度:rgba
5.圆角:border-radius
6.阴影:box-shadow
7.背景效果:background-size
8.转换: transform transition
51.html5语义化标签
1.语义化标签
<header>, <nav>, <footer>, <artical>, <main>, <aside>, <section>
2.音频视频标签
视频:<video>
音频: <audio>
3.canvas绘图
初始:宽300px 高150px
4.SVG绘图
5.webSocket
websocket创建和常用的属性方法
var websocket = new websocket(url);
websocket.onopen=function() {//在链接建立时触发}
websocket.onclose=function() {//链接关闭时触发}
websocket.onmessage=function(){//客户端接受服务器数据时}
websocket.send('发送数据')
6.增强型表单
类型 描述
color 主要用于选取颜色
date 一个日期选择器选择一个日期
email 包含e-mail地址的输入域
month 选择一个月份
number 数值的输入框
tel 定义输入电话号码
7.新增表单属性
placehoder 输入前显示在输入框内,用户输入消失
required 要求输入框不能空
min和max 设置元素最小值与最大值
autofocus 自动获取焦点
multiple input可选择多个值
canvas与上svg的区别
1.svg绘制出来的每一个图形的元素都是独立的dom节点,能够方便的绑定事件或用来修改,canvas输出的是一整张画布。
2.svg输出的图形是矢量图形,后期可以修改参数来自由放大缩小。不会失真和锯齿。而canvas输出标量画布,像一张图片一样,放大会失真或者锯齿。
52.响应式开发适配的机型
响应式:基于一套代码,开发一个app能够兼容多尺寸,多终端设备的显示,能够动态调整页面的布局及容器的布局。
设备划分 尺寸区间 宽度设置
超小屏(手机) <768px 100%
小屏幕(平板) >=768~992px 750px
中等屏幕(桌面显示器) >=992px~1200px 970px
宽屏设备(大桌面显示器) >=1200px 1170px
53.微前端
微前端就是将不同的功能按照不同的维度拆分成多个应用,通过主应用加载这些子应用。
微前端的核心在于拆,拆完后再合。
54.原声事件与React合成事件的区别
1.react合成事件是绑定在document上的,原生事件是绑定在dom上。
相对绑定的地方,dom事件要优先于document上的事件执行
2.原生事件阻止事件冒泡:event.stopPropagation
react事件阻止事件冒泡:event.preventDefault
3.阻止原生事件的冒泡后,会阻止合成事件之行
55.等式是否成立
0.1+0.2 == 0.3 // false
怎么使等式成立 0.1跟0.2分别乘以100再相加,然后再除以100
{} == {} //false
虽然值一样,但栈中保存的实际上是指向堆中对象的一个指针,值一样,但是是独立的两个对象占两份内存空间
1==true //true
在==的隐式转换中,把两边都进行了number转换
undefined === undefined //true
null === null // true
null == undefined //true
NaN == NaN //false
56.['1', '2', '3'].map(parseInt)结果
结果为[1, NaN, NaN]
parseInt函数接收两个参数parseInt(string,radix)
string: 需要被解析的字符串
radix: 要解析的数字的基数 该值介于2~36
['1', '2', '3'].map(parseInt) 即
parseInt('1', 0) parseInt会根据十进制解析,结果为1
parseInt('2', 1) parseInt超出区间范围 NaN
parseInt('3', 2) parseInt用2进行解析,应以0和1开头 NaN
57.HTTP状态码
58.
Math.ceil() 执行向上舍入 ceil英文意思天花板,所以向上取
Math.floor() 执行向下舍入 floor英文意思地板,所以向下取
Math.round() 执行标准舍入,四舍五入
如果小数为0.5,则四舍五入到相邻的正无穷方向上的整数
比如: Math.round(4.5) //5 Math.round(-4.5) // -4
59.构造函数与class的区别
1.类的形式
可以在class内部同时定义普通对象的属性与方法,定义构造函数对象上的方法,定义原型上的方法属性。
值得注意的是通过静态关键字只能在构造函数对象上添加方法,也就是说只能定义静态的方法,不能定义静态的属性
2.构造函数的形式
在构造函数内部只能定义普通对象上的方法和属性
静态方法也就是构造函数对象上的方法,只能通过显示的追加
原型对象上面的方法和属性也需要显示追加
60.创建对象的方式
1.工厂模式
例:function createPerson (name, age, job) {
let obj = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayNam = function() {
console.log(this.name)
}
}
let person = createPerson('lhh', '14', 'IT');
2.构造函数模式
例:function Person (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayNam = function() {
console.log(this.name)
}
}
let person1 = new Person('lhh', '14', 'IT');
let person2 = new Person('lhh', '15', 'IT');
61.原型实现继承的方式
1.原型链继承
例:function Dog() {
this.dog = 'dog';
}
function Cat() {
this.cat = 'cat';
}
cat.prototype = new Dog();
let newCat = new Cat();
2.借用构造函数 (缺点:继承不到父类原型上的方法和属性)
例:function Super (name) {this.name = name}
function Suber () {
Super.call(this, 'kies');
this.age = '27';
}
let oo = new Suber();
console.log(oo.name); //kirs
3.组合继承
使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。这样使得定义在原型上的方法实现函数复用,又能够保证每个实例都有自己的属性
62.JS回收机制
JS垃圾回收机制是为了防止内存泄漏的,(已经不需要的某一块内存还一直存在着),垃圾回收机制就是不停歇的寻找这些不再使用的变量,并释放掉它所指向的内存
垃圾回收方法?
标记清除法:当声明变量的时候,垃圾回收器将该变量进行标记,当该变量离开环境时,将其再度标记,随之进行删除
63.E charts开发中遇到的问题
1.Echarts解决双Y轴,左右刻度不一致
解决办法:
1:求出一组数据的最大值,这里设置最大值为10的倍数
2.根据最大值,设置interval
function calMax (arr) {
var max = arr[0];
for(let i = 0; i< arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
var maxInt = Math.ceil(max/10); //向上取整
var maxVal = maxInt*10; // 最终设置的最大值
return maxVal;
}
var appRegum = [10,20,30,40,50,....,130];
var activeNum = [1.1,2.2,3.3,4.4,5.5,...,30.5];
var maxAppRegum = calMax(appRegum); //注册Y轴值
var maxActive = calMax(activeNum); //活跃Y轴值
var interval_left = maxAppRegum / 5; //左轴间隔
var interval_right = maxActive / 5; //右轴间隔
option = {
...,
yAxis: [
{
type: 'value',
name: '注册',
min: 0,
max: maxAppRegum,
invertal: interval_left,
splitNumber: 5,
},
{
type: 'value',
name: '活跃',
min: 0,
max: maxActive,
invertal: interval_right,
splitNumber: 5,
}
]
}
2.echarts的父级要有宽高,否则就显示不出来
64.盒模型分为什么
标准盒模型: width = content
怪异盒模型: width = content + padding + border
box-sizing: border-box; //转换为怪异盒模型
65. 清除浮动的方式
1.overflow: hidden;
2.给父级添加伪元素
.clear::after {
display: block; // clear 属性只有块级元素才有效,而::after等伪元素默认是内联
content: '';
clear: both;
}
66.css布局的几种方式
1>flex布局
2>float 布局
3>响应式布局
4>文档流布局
67.this指向
非严格模式下this指向默认的window,严格模式下,this指向undefined
普通函数调用:this指向全局对象window
对象函数调用:谁调用this就指向谁
对象函数调用:this指向实例对象
箭头函数:
1.箭头函数的this是在定义函数的时候绑定的,继承父级执行上下文中的this(注意:简单对象是没有执行上下文的)。
2.可以解决匿名函数和定时器的this指向问题,不用用变量that存储this
70.懒加载
懒加载:优先加载可视区域的内容,其他部分等进入了可视区域在加载。
原理:先把img的src指向空或者一个小图片,图片的真实地址存在img的一个自定义属性里,<img src='' data-src='http://.......red.jpg' />,等到此图片出现在可视区域内,获取img元素,把data-src赋值给src.这样防止页面一次性向服务器响应大量请求,导致服务器响应慢,页面卡顿或崩溃等问题。
判断图片是否出现在可视区域:
img的offsetTop < document.documentElement.clientHeight + document.documentElement.scrollTop
71.sass使用的哪些功能
1.$声明变量
2.&引用父元素 如: a { &:hover {color: red;} }
3.可嵌套
4.计算功能 +,-,*, /
5.继承
如: .a1 {color: red;} .a2 {@extend .a; font-size: 12px}
6.混合 用来分担那些需要在页面中复用的css声明,开发人员可以通过MIXIN传递变量参数,让代码更加灵活。
如:
@mixin boreder-radius ($value) {
border-radius: $value;
-webkit-border-radius: $value;
-o-border-radius: $value;
-ms-border-radius: $value;
-moz-border-radius: $value;
}
.box {@include border-radius(5px); }
如: @mimin banner {
width: 100%;
position: relative;
}
.lead-banner {
@include banner;
}
72.ref的3种用法
1.字符串 (dom节点上使用通过this.refs[refname]来引用真实的dom节点)
<input ref='inputRef' /> //this.refs.inputRef
2.回调函数
<input ref={(input) => {this.textInput = input}} />
3.React.createRef()
在react 16.3版本后,使用此方法创建ref。将其赋值给一个变量,通过ref挂载到dom节点或者组件上,该ref的current属性能拿到dom节点或组件实例。
class Child extends React.component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount() {
console.log(this.myRef.current)
}
render(){
return <input ref={this.myRef} />
}
}
74.var a=b=5;
1.解析: var a=b; b=5;
2.然后,b=5前面没有var,相当于声明为全局变量
3.相当于:
var b;
(function...{var a=b; b=5;})();
console.log(b) //5
console.log(a) //a is not defined
75.link与@import的区别
1.link是标签 @import 是css提供的一种方式
2.加载顺序差别,页面加载link会同时加载,@import 会等页面全部被下载再加载
3.兼容性。@import会有兼容性问题,link没有
76.为什么用transform中的translate,不用定位实现移动
性能问题,定位在手机上会出现卡顿。
使用绝对定位会触发回流和重绘,造成页面卡顿,translate不会触发回流或重绘
77.扩展运算符使用场景
1.数组和对象的浅拷贝
2.字符串转为数组
3.伪数组转换为数组
4.合并数组
5.函数形参
78.什么情况会造成内存泄漏
1.意外的全局变量引起内存泄漏。(直接赋值的变量)
2.闭包引起的内存泄漏
3.没有清理的dom元素引用
4.被遗忘的定时器
79.React性能优化方案
1.给按钮绑定事件的时候,最好在constructor内进行绑定如:
class App extends React.Component {
constructor (props) {
super(props)
this.onClick=this.onClick.bind(this);
}
render(){
return(<button onClick={this.onClick}>按钮</button>)
}
}
2.当父组件变化时,而且子组件并没有变化,此时组件也会同时render
可以使用shouldComponentUpdate进行优化
React.component创建组件换成React.pureComponent
3.对于数组形式的数据,遍历时需要给同级的每个值添加独一无二的key
80.BFC的理解
BFC是块级格式化上下文,一个元素形成BFC之后,它的内部元素布局不会影响到外部元素,外部元素不会影响到内部元素。
形成BFC的方式:
1.浮动元素与绝对定位元素
2.display属性值为inline-block,flex,table,flex
3.元素的overflow值不为默认属性(visible)
使用场景:
1.清浮动
2.解决margin重叠问题(外边距为两者中的最大值,重叠只会出现在垂直方向)
3.自适应两栏布局
.left {float: left; width: 100px; height: 300px;}
.right {overflow: hidden; height: 300px;}
81.从哪些点做性能优化?
1.加载
减少http请求(精灵图-雪碧图,文件的合并)
减少文件大小(资源压缩,图片压缩,代码压缩)
CDN(第三方库,存放大文件大图片,代码中引入地址)
SSR服务端渲染,预渲染
懒加载
分包
2.减少dom操作,避免回流,文档碎片
3.css性能的优化
css压缩
使用margin-top,margin-bottom来设置而不是用margin:top 0 bottom 0;
尽量使用link标签,而不要使用@import
82.jsx是什么
jsx是js的一种扩展语法,它不能被浏览器读取,需要通过babel将其解析为传统js.
为什么要使用jsx?
jsx允许前端开发者使用我们最熟悉的html标签语法来创建虚拟dom,在降低学习成本的同时,也提高了研发效率和体验
83.React的生命周期
1.挂载时
constructor--getDerivedStateFromProps--render--componentDidMount
2.更新时
getDerivedStateFromProps--shouldComponentUpdate--render--getSnapShotBeforeUpdate--componentDidUpdate
3.卸载时
componentWillUnmount
84.高阶组件使用场景以及优缺点
1.权限控制
function withAdminAuth (wrapComponent) {
return class extends React.component {
state={isAdmin: false}
componentWillUnmount() {
this.setState({isAdmin: 'Admin'})
}
render() {
if(this.state.isAdmin){
return <wrapComponent {...this.props} />
} else {
return (<div>您没有权限,请联系管理员</div>)
}
}
}
}
优点:通过传递props去影响内层组件状态,不影响参数组件的内部逻辑,降低了耦合度
缺点:组件多层嵌套,增加复杂度与理解成本
高阶组件多层嵌套,相同属性名的props会覆盖老属性,不清楚props来源于哪个高阶组件
85.柯里化函数?
题目:实现函数fn,让其具有如下功能;let res = fn(2,1)(3); console.log(res) //6
function fn (...others) {
return function(...innerOther) {
let args = innerOther.concat(others);
return args.reduce((result, item) => result+item);
}
}
题目:编写一个求知函数sum,使输入sun(2)(3)或输入sum(2,3),输出结果为5;
function sum(other) {
var num = other[0];
if (other.length == 1) {
return function(sec) {
return num+sec;
}
} else {
return other.reduce((result, item) => result+item)
}
}
86.类组件与函数组件哪个性能好,为什么?
函数组件性能好,函数组件不回有组件实例化的过程,不需要分配多余的内存,函数组件没有生命周期。
87.jsonp的实现原理
1.首先利用script标签的src属性来实现跨域
2.通过将前端方法作为参数传递到服务器,然而由服务器注入参数之后返回,实现服务器端向客户端通信
3.由于使用script标签的src属性,因此只支持get方法。
实现:
1.设定script标签
<script src='http://jsonp.js?callback=xxx'></script>
2.callback定义一个函数,而远程服务端通过调用指定函数来实现传递参数,将fn(response)传递回客户端
3.客户端接收到返回的js脚本,开始解析和执行fn(response)
88.在antd的基础上写自定义筛选菜单
使用columns的filterDropdown属性,自定义筛选菜单。为了可复用性高将其封装为一个函数
该函数只需要传入筛选操作时发生时要执行的函数其他参数从antd给的props里取。由此依然可以用antd的filter等api.返回一个完整的菜单组件
export const getColumnFilter = onSearch => void => props => {
const { setSelectedKeys, selectedKeys, filters, confirm, clearFilters } = props;
const onChange = (checkedValues) => {setSelectedKeys(checkedValues)}
const clear = () => {
setSelectedKeys([]);
onSearch([]);
clearFilters([]);
}
const onOk = () => {
onSearch(selectedKeys);
confirm();
}
return (
<div>
<Checkbox.Group onChange={onChange} value={selectedKeys}>
{
filters.map(
item => (
<Checkbox value={item.value} key={item.value}>
{item.text}
</Checkbox>
)
)
}
</Checkbox.Group>
<div>
<Button onClick={clear}>reset</Button>
<Button onClick={onOk} type='primary'>ok</Button>
</div>
</div>
)
})
在定义的table columns时使用
{
dataIndex: 'sth',
title: 'sth',
filters: [
{text: 'filter1', value: 'filter1'},
{text: 'filter2', value: 'filter2'}
],
filterDropdown: getColumnFilter(//onSearch func like setData)
}