html、css 这些基础知识,自行查找。这里只分享干货。
js常见的例题
数据类型 6 + 3
-
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
-
引用数据类型:对象(Object)、数组(Array)、函数(Function)。
关于 promise、setTimeout、异步执行的顺序问题。
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
答案: script start / async1 start / async2 / promise1 / script end / async1 end / promise2 / setTimeout
解析:js是基于事件驱动单线程执行的,执行顺序 代码自上而下。
-
第一步: script start , 虽声明了两个函数,但都没
调用,因此 输出 “ script start” ; -
第二步: async1 start , 执行到setTimeout时,但并不会打印
setTimeout。会直接走到下一步,执行async1() ;-
解析为什么并不会打印
setTimeout?-
我们知道,JavaScript是基于事件驱动单线程执行的,所有任务都需要排队,也就是说前一个任务结束,才会去执行下一个任务。而像setTimeout、ajax等异步操作的回调,会进入”任务队列“中,而且只有主线程中没有执行任何同步代码的前提下,才会执行异步回调。而setTimeout(fn, 0)表示立即执行,也就是用来改变任务的执行顺序,要求浏览器
尽可能快的进行回调。 -
虽然参数2 为0,但并不代表这
0秒之后执行setTimeout的代码,正确的解释是,0秒之后你可以执行了,但并不意味着你可以执行,只是代表这 浏览器将你这个任务接收了,已经插入到任务队列当中了,但必须需要等待我所有程序执行完毕才可以执行此任务。 -
0秒其实是
假象,setTimeout有个最小执行时间4ms minimum delay of 4ms注:HTML5中已经将最小执行时间统一为4ms。
-
这里有一个例子可更清晰的解释;参考文章 你应该知道的setTimeout秘密
var start = new Date(); var end = 0; setTimeout(function() { console.log(new Date() - start); }, 500); while (new Date() - start <= 1000) {} 你是不是觉得打印结果为:500, 然而并不是,打印结果为 : 1004 (也许你打印的不一样,但肯定大于 1000) 虽然setTimeout的延时时间是500毫秒,可是由于while循环的存在,只有当间隔时间大于1000毫秒时, 才会跳出while循环,也就是说,在1000毫秒之前,while循环都在占据着JavaScript线程。 也就是说,只有等待跳出while后,线程才会空闲下来,才会去执行之前定义的setTimeout。 最后 ,我们可以总结出,setTimeout只能保证 在指定的时间后将任务(需要执行的函数)插入任务队列中等候, 但是不保证这个任务在什么时候执行。 一旦执行javascript的线程空闲出来,自行从队列中取出任务然后执行它。 实在不理解,去看上述 文章。
-
-
-
第三步:async1 start ,setTimeout将任务进行等待,所以执行函数
async1 () -
第四步: async2 ,继续执行
async1()函数的结果,且返回promise对象 -
第五步: promise1, async1()函数中包含关键词
await,'async1 end' 并不会执行,会一直等待其他非await程序执行完毕。 new Promise() 是立即执行函数,所以执行promise1,promise2不执行和 上述同理 -
第六步: script end , 因为上一步先打印了promise1,然后执行到resolve的时候,然后跳出promise继续向下执行,输出script end
-
第七步:async1 end, 返回promise对象开始执行。
-
第八步: promise2 , 返回promise对象开始执行。
-
第九步: setTimeout,最终才执行。因为所有任务已经执行完毕。
深拷贝和浅拷贝
本文思维导图如下:
深拷贝方法:
- 简单方法:
JSON.parse(JSON.stringify( )); - 递归
/**
* 递归深拷贝
* */
function deepClone(origin) {
let target = origin ;
let isDate = Object.prototype.toString.call( origin ) === '[object Date]' ;
let isRegExp = Object.prototype.toString.call( origin ) === '[object RegExp]' ;
if(typeof origin === "object" && origin !== null && !isDate && !isRegExp){
target = Array.isArray(origin) ? [] : {} ;
for(let key in origin){
if(origin.hasOwnProperty(key)){
target[ key ] = deepClone(origin[key])
}
}
}
return target ;
}