Javascript执行上下文顺序的深入讲解
一执行上下文?
1什么是执行上下文?
执行上下文就是当前的JavaScript代码被解析和执行时所在环境的抽象概念,JavaScript中运行任何的代码都是在执行上下文中运行的.
2执行上下文的类型
执行上下文分为三种类型:
全局执行上下文:只有一个,这是默认的,也是基础的执行上下文.(不在任何函数中的代码都是全局执行上下文)他有两个作用,一个是创建了全局变量,也就是指向window下的变量,另一个是将this的指向全局.
函数执行上下文:有无数个,每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建,每次调用时,都会为该函数创建一个新的执行上下文…
Eval函数执行上下文:指的是运行在eval函数中的代码,很少用而且不建议使用。
二执行上下文的生命周期
1.创建阶段
执行上下文的生命周期有三个阶段:创建阶段–执行阶段—回收阶段(主要说创建阶段)
当函数被调用,但没有执行任何其内部代码之前,会先确定这三个步骤:
1)创建变量对象:首先初始化函数的参数arguments,提升函数声明和变量声明
2)创建作用域链:在执行期上下文的创建阶段,作用域链是在变量对象之后创建的.作用域链本身包含变量对象。
作用域链用于解析变量。当被要求解析变量时,JavaScript始终从代码嵌套的最内层开始,如果最内层没有
找到变量,就会跳转到上一层父作用域中查找,直到找到该变量。
3)确定this指向:有多种情况.
2.执行阶段
执行变量赋值、代码执行
3.回收阶段
执行上下文出栈等待虚拟机回收执行上下文
三.变量提升和this的指向
1.变量声明提升:
大部分编程语言都是先声明变量再使用,但在JS中,事情有些不一样:
console.log(a);//undefined vara=10;
上述代码正常输出undefined而不是报错UncaughtReferenceError:aisnotdefined,这是因为声明提升.
相当于:
vara;//声明默认值是undefined“准备工作” console.log(a); a=10;//赋值
2.函数声明提升
创建函数的方法有两种,一种是通过函数声明functionaa(){}
另一种是通过函数表达式varaa=function(){},那这两种在函数提升有什么区别呢?
console.log(f1);//functionf1(){}
functionf1(){}//函数声明
console.log(f2);//undefined
varf2=function(){};//函数表达式
接下来我们通过一个例子来说明这个问题:
functiontest(){
aa();//UncaughtTypeError"aaisnotafunction"
bar();//"thiswillrun!"
varaa=function(){
//functionexpressionassignedtolocalvariable'aa'
alert("thiswon'trun!");
};
functionbar(){
//functiondeclaration,giventhename'bar'
alert("thiswillrun!");
}
}
test();
在上面的例子中,aa()调用的时候报错了,而bar能够正常调用。
我们前面说过变量和函数都会上升,遇到函数表达式varaa=function(){}时,首先会将varaa上升到函数体顶部,然而此时的aa的值为undefined,所以执行aa()报错。
而对于函数bar(),则是提升了整个函数,所以bar()才能够顺利执行。
细节必须注意:当遇到函数和变量同名且都会被提升的情况,函数声明优先级比较高,因此变量声明会被函数声明所覆盖,但是可以重新赋值。
alert(a);//输出:functiona(){alert('我是函数')}
functiona(){
alert("我是函数");
}//
vara="我是变量";
alert(a);//输出:'我是变量'
function声明的优先级比var声明高,也就意味着当两个同名变量同时被function和var声明时,function声明会覆盖var声明
这代码等效于:
functiona(){
alert("我是函数");
}
vara;//hoisting
alert(a);//输出:functiona(){alert('我是函数')}
a="我是变量";//赋值
alert(a);//输出:'我是变量'
3.确定this指向
//情况1
functionfoo(){
console.log(this.a)//1
}
vara=1
foo()//this->window
//情况2
functionfn(){
console.log(this);
}
varobj={fn:fn};
obj.fn();//this->obj
//情况3
functionCreateJsPerson(name,age){
//this是当前类的一个实例p1
this.name=name;//=>p1.name=name
this.age=age;//=>p1.age=age
}
varp1=newCreateJsPerson("尹华芝",48);
//情况4
functionadd(c,d){
returnthis.a+this.b+c+d;
}
varo={a:1,b:3};
add.call(o,5,7);//1+3+5+7=16
add.apply(o,[10,20]);//1+3+10+20=34
//情况5
箭头函数this
letbtn1=document.getElementById('btn1');
letobj={
name:'kobe',
age:39,
getName:function(){
btn1.onclick=()=>{
console.log(this);//obj
};
}
};
obj.getName();
结果:
1this指向window;
2谁调用了函数,谁就是this,所以在这个场景下foo函数中的this就是obj对象
3在构造函数中,this是当前类的一个实例
4call、apply和bind:this是第一个参数
5箭头函数this指向:箭头函数没有自己的this,看其外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window。
到此这篇关于Javascript执行上下文顺序的文章就介绍到这了,更多相关Javascript执行上下文顺序内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!