#1、js同步和异步的理解以及宏任务和微任务
(1)同步:从头到尾 ,一行一行执行代码
例子:
console.log(1)
console.log(2)
打印出来就是 1,2 从头到尾执行代码
(2)异步:可以改变程序正常执行顺序(从头到尾)的操作就可以看成是异步操作。
js是一门单线程的语言,因此如果在js线程中出现耗时操作,就容易堵塞后续代码的执行。因此在js中如果碰到一些可能需要消耗一些时间的操作,像setTimeout,ajax的回调函数(称其为异步操作)等,js会将其放入一个代办任务队列taskqueue中,当js按顺序执行完其它同步的,不耗时的操作之后,会去依次执行taskqueue队列中的任务。
例子
console.log(1)
setTimeout(()=>{
console.log(2)
},0)
console.log(3)
显然打印的结果为 132
(3)宏任务和微任务
宏任务:普通的script代码(同步代码),setTimeout,setInterval
微任务:process.nextTick,promise.then()
js在执行完同步代码之后,会首先去执行微任务队列中待执行的代码,然后再去执行宏任务中的代码
所以
setTimeout(()=>{
console.log(1)
},0)
new Promise((resolve)=>{
console.log(2);
resolve();
}).then(()=>{
console.log(3)
})
console.log(4)
注:Promise是同步代码,Promise.then()是微任务
打印的结果为 2431
注:当问到vue的this.$nextTick()可以 结合说说
#2、js的深浅拷贝
js的数据类型
Number(数值型) String(字符串型) Boolean(布尔型) Object(对象,object和arr都属于对象类型) null undefined
日常使用的javascript深浅拷贝主要是面向Object引用类型进行拷贝
深浅拷贝的概念:
深浅拷贝主要是对js引用类型进行拷贝
拷贝顾名思义就是复制,内存中一共分为栈内存和堆内存两大区域
浅拷贝: 引用类型数据相互赋值之后,例如 obj1 = obj2;如果后面操作修改obj1或者obj2,这两个数据会同时变化,因为内存中引用类型数据是堆内存中,堆内存中存放的是引用类型的值,同时会有一个指针地址指向栈内存,两个引用类型数据地址一样,如果其中一个发生变化另外一个都会有影响
深拷贝:而深拷贝不会,深拷贝是会在堆内存中重新开辟一块空间进行存放
基本数据类型的复制
var a = 1;
var b = a; //复制
console.log(b) ; //1
a = 2;
console.log(a) //2
console.log(b) //1
a,b都是基本类型,基本类型的复制不会影响对方的
基本类型是每一次创建变量都会在栈内存中开辟一块内存,用来存放值。
引用类型(Object Array)复制
(1)js浅拷贝(复制)
var arr1 = [1, 2]
var arr2 = arr1; //复制
console.log(arr2); //[1,2]
arr1[0] = 3; //改变值
console.log(arr1) //[2,2]
console.log(arr2) //[2,2]
var arr2 = arr1; 是将两个引用类型的数据的地址指针指向了同一块堆内存中,所以不管是arr1还是arr2修改,任何一个改变,两个数组都会相互产生影响;这种直接赋值的方式的复制就是引用类型的浅拷贝。
(2)js深拷贝
一维数组的深拷贝
var arr1 = [1, 2]
var arr2 = arr1.slice(0); //复制方法一 原生的slice
var arr2 = arr1.concat(); //复制方法二 原生的concat
var arr2 = arr1.map(item=>item); //复制方法三 es5
var arr2 = [...arr1]; //复制方法四 es6的解构
console.log(arr2); //[1,2]
arr1[0] = 3; //改变值
console.log(arr1) //[3,2]
console.log(arr2) //[2,2]
上面的4种方法 都会返回一个新的数组 ,从而实现了一维数据的深复制
不过 如果是二维数组 就有问题
二维数组的深拷贝
js数组中实现深拷贝的方法都多种,比如JSON.parse(JSON.stringify())和递归以及JQuery库的extend方法(只是extend方法需要依赖JQuery库,所以我们尽量的使用原生的方式来实现)都是可以实现数组和对象的深拷贝的;
var arr1 = ['red','green'];
var arr2 = JSON.parse(JSON.stringify(arr1));//复制
console.log(arr2)//['red','green'];
arr1.push('black') ;//改变color1的值
console.log(arr2)//["red", "green"]
console.log(arr1)//["red", "green", "black"]
JSON.parse(JSON.stringify())是真正意义上实现了深拷贝;
拷贝一个字符串会新辟一个新的存储地址,这样就切断了引用对象的指针联系,所以先转成一个字符串,在解析出对象,这样就可以深拷贝一个对象
注:json拷贝的缺陷
(1)如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
(2)如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象;
递归实现深拷贝
function deepClone(obj){
//判断参数是不是一个对象
let objClone = obj instanceof Object?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
var a ={
x:1,
y:2
};
b=deepClone(a);
a.x=3
console.log(a);
console.log(b);
总结:
1:深拷贝只是从原数据中拷贝一份出来进行操作,而不是改变源数据;改变原数据的那是浅拷贝;
2:原生js方法slice、concat都不是真正意义上的深拷贝,都仅只适用于一维数组,拷贝的属性不够彻底;
3:实现js深拷贝我们可以通过JSON.parse(JSON.stringify())、递归以及JQuery库的extend方法来实现;
3、对promise理解
promise是什么
Promise是最早由社区提出和实现的一种解决异步编程的方案,比其他传统的解决方案(回调函数和事件)更合理和更强大。
ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。
promise特点
(1)Promise对象代表一个异步操作,有三种状态:
pending 异步操作未完成 (初始状态)
resolved 异步操作成功,又称为Fulfilled (成功状态)
rejected 异步操作失败 (失败状态)
(2)
Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,只能由 pending变成fulfilled或者由pending变成rejected
Promise的三个缺点
1)无法取消Promise,一旦新建它就会立即执行,无法中途取消
2)如果不设置回调函数,Promise内部抛出的错误,不会反映到外部
3)当处于pending状态时,无法得知目前进展到哪一个阶段,是刚刚开始还是即将完成
Promise.all()实行多任务并行
开发有用到 比如说首页的并行加载