本文涉及知识点:
1、提升(这里有变量提升和函数提升);
2、js的单线程特性
3、setTimeout函数的执行机制
首先我们来看一下题目,这是一道选择题,有四个选项。
这段代码在具体开始运行的时候,是怎么样呢。(为了语言精确点,我在下面摘抄了《你不知道的JS》中的表述方式。摘抄部分我用引号括起来)
1、提升
(1)Why?(为什么存在提升这么个知识点)
“引擎会在解释JS代码之前首先对其进行编译。编译阶段中的一部分工作就是找到所有的声明,并用合适的作用于将他们关联起来。”
也就是:“包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理”
“比如 var a = 2;
我们执行的时候会以以下形式处理:
var a;
a=2;
”
所以说,你要知道JS代码在运行的时候,有两个阶段,第一个是编译阶段,会有提升,第二阶段是执行阶段,就是表达式的执行。
(2)What (什么是提升)
源代码
console.log(a); //表达式
var a = 2;//变量声明加赋值
在实际处理的过程是:
var a; //变量提升
console.log(a);//其他的表达式按顺序
a = 2;
变量和函数声明从它们的代码中出现的位置被“移动”到了最上面。这个过程就叫提升。
只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。
(3)函数优先
函数声明和变量声明都会被提升,但是函数首先被提升,然后才是变量。同名的函数,后面的函数声明可以覆盖前面的。
(4)拓展下这道题没用到的点
就是函数声明,命名冲突的,后面会覆盖前面。
但是变量声明(初始化为undefineg),如果命名冲突了,会忽略。
比如:
function foo(x,y,z){
function func(){};
var func;
console.log(func);
}
foo(100);
运行结果为 function func(){};
因为这里函数func被声明之后,变量func去查找,发现已经被声明了,就会忽略这次变量声明。
所以实际运行过程就是:
function foo(x,y,z){
function func(){};
console.log(func);
}
foo(100);
但是我们换一段代码再加深下理解:
function foo(x,y,z){
function func(){};
var func = 1;
console.log(func);
}
foo(100);
这里的结果显示就是 1 了。因为这里虽然变量声明被忽略了,但是那句赋值语句还是在的。所以实际代码就是:
function foo(x,y,z){
function func(){};
func = 1; //在这里func就已经被赋值为1了
console.log(func);//打印1
}
foo(100);
2、js的单线程特性
js是个单线程的语言,所以如果说遇到setTimeout、setInterval、ajax请求等需要停顿的语句,就停下来等这个停顿时间过去的话,语言的运行就阻塞在这里了。所以说,js就想了个办法,那就是我遇到setTimeout这样停顿类的语句,不管你停顿多久吧(可能是停顿0),都一律跳过去,等那些不需要停顿的语句执行完了,再回过头来执行需要等待的语句。
“js引擎单线程执行的,它是基于事件驱动的语言.它的执行顺序是遵循一个叫做事件队列的机制.浏览器有各种各样的线程,比如事件触发器,网络请求,定时器等等.线程的联系都是基于事件的.js引擎处理到与其他线程相关的代码,就会分发给其他线程,他们处理完之后,需要js引擎计算时就是在事件队列里面添加一个任务. 这个过程中,js并不会阻塞代码等待其他线程执行完毕,而且其他线程执行完毕后添加事件任务告诉js引擎执行相关操作.这就是js的异步编程模型.”
所以这里timeLoop函数会在两个setTimeout函数之前执行。
3、setTimeout函数的执行机制
setTimeout:在指定时间内, 将任务放入事件队列,等待js引擎空闲后被执行.
好,言归正传,我们对这道面试题的实际执行过程如下:
var w1Date;
var w2Date;
function w1(){
w1Date = Date.now();
}
function w2{
w2Date = Date.now();
console.log('time sp:' + w2Date - w1Date + 'ms');
}
function timeLoop(k){
var now
now = Date.now();
while(Date.now() - now < k){}
}
timeLoop(500);
setTimeout(w1,100);
setTimeout(w2,200);
所以这里两个setTimeout被加入事件队列中。但是因为函数timeLoop的功能是空跑500ms,所以已经超过了两个函数需要的延时,于是,两个都在timeLoop函数执行完后,立刻运行了。因此两个setTimeout函数运行的的时间是非常短的。所以这道题选A.
js新人,欢迎大神批评指正。拜谢。