一、执行上下文
1、什么是执行上下文?
分析一个问题之前,首先我们都需要知道它是什么。执行上下文又称词法环境,它是存储和处理数据的栈,主要分为两部分:
预处理阶段:
①在这个阶段它会将所有的var类型的变量存入上下文中并给它赋值为undefined;
②除此之外,它还会将声明的函数存入栈中,并将函数体赋值给它。
③还有一个就是this对象执行阶段:
①给词法环境中的变量进行赋值
②如果词法环境中不存在这个变量,就把它加入到词法环境并给它赋予相应的值。
2、变量名、函数名冲突问题
如果多个人写js代码,冲突问题是很难避免的,所以我们需要知道什么时候会发生冲突问题,然后改怎么解决。
1)产生冲突问题的情况
①预处理过程:如果两个函数名相同,后面的会覆盖前面的,即使里面的参数个数不同,也会进行覆盖。
console.log(fun1);
fun1();
function fun1(){
console.log("执行fun1函数");
}
function fun1(val){
console.log("aaa");
}
这里会输出”aaa”而不是“执行fun1函数”。
②执行阶段:
- 执行阶段不会再处理声明方式定义的函数;
- 声明方式定义函数不会覆盖任何定义的函数和属性
- 后赋值的属性会覆盖先赋值属性内容
③优先级:声明的函数>用var定义的变量;因此,当函数先声明,变量后声明,名字相同但是变量不会将函数进行覆盖,而是将它忽略。
3、案例分析
- 案例一
console.log(a);
console.log(b);
console.log(fun1);
console.log(fun2);
var a=10;
b=20;
fun1();
fun2();
function fun1(){
console.log("执行了fun1函数");
}
var fun2=function(){
console.log("执行了fun2函数");
}
一旦代码执行,就会产生一个全局上下文,函数只有被调用的时候才会产生上下文。综上可知,在预处理阶段,全局上下文中会有三个变量,分别为a=undefined fun1(){} fun2=undefined;当执行第一行代码的时候,因为在全局上下文中a还没有被赋值,所以输出undefined;而全局上下文中并没有b,所以这里输出b程序会报错;同理,fun1就是输出它的函数体;fun2=undefined;
当执行到fun1()时,由于fun1在全局上下文中有函数体,所以可以正常输出;而fun2()在全局上下文中仍是undefined,所以这个时候被调用时会报错的。
案例2;
function fun(a,b){
console.log(a);
console.log(b);
var a=20;
function b(){
console.log("执行了b函数");
}
}
fun(1,2);
总共产生了三个上下文,预处理阶段如图所示,由于在fun()中b发生了冲突,由于声明的函数比变量的优先级要高,所以b(){}会将变量b进行覆盖;当执行fun(1,2)这行代码时,a的值会变为1,而执行阶段不会再处理声明方式定义的函数,因此b的输出仍然函数b(){}。
二、作用域
之前学其他语言的时候,也都听说过作用域这个概念,简单来说就是可以使用的范围。与其他语言不通的是,js中的作用域没有块级域之说,不会以{}来进行作用域的分离。
for(var i=0;i<5;i++){
var str="aaa";
}
console.log(i,str);
//这里虽然是在for循环里面定义的变量,但是在js中在全局仍可以访问的到
js中的作用域主要分为部分:全局作用域和本地作用域。
作用域和上下文的区别:作用域是在代码写完后作用域就已经确定好了,而上下文会因为代码的执行而发生改变。
- 整个页面只有一个全局作用域
- 全局域有一个内置对象,window
- 所有全局域的变量和方法都绑定到window对象上