一、js中的词法作用域和动态作用域
词法作用域也就是在词法阶段定义的作用域,也就是说词法作用域在代码书写时就已经确定了。
js中其实只有词法作用域,并没有动态作用域,this的执行机制让作用域表现的像动态作用域,this的绑定是在代码执行的时候确定的。
example1: 理解词法作用域
记住js中只有词法作用域没有真正的动态作用域,作用域是在代码书写时确定的
var value = 1; function foo() { console.log(value); } function bar() { var value = 2; foo(); } bar();
//1
输出是1,函数在哪里调用没有关系,变量的位置在编译的词法分析阶段就确定了。
当调用foo时,会对value进行一次RHS查询,在当前函数作用域中没有查找到会查找到最外层的作用域,也就是全局作用域定义的value。
二、修改词法作用域
在代码书写时,作用域(词法作用域)就已经确定了,但是可不可以再修改呢?
通过eval和with都可以用来修改词法作用域。
eval:
function foo(str, a) {
eval(str)
console.log(a, b)//1,3
} var b = 2;
foo("val b = 3", 1)
with:
用来重复引用同一个对象中的多个属性的快捷方式
可以理解为修改对象中多个属性的值的快捷方式
function foo(obj) {
with(obj) {
a = 7
}
} var obj1 = {
a: 2
} var obj2 = {
b: 3
} foo(obj1)
console.log(obj1)// {a=7}
console.log(a) //7
foo(obj2)
console.log(obj2)//{b:3}
console.log(a)//7
with可以定义一个词法作用域, 值得注意的是with中定义的a=2会在全局作用域中包含一个a变量。
三、函数作用域和块作用域
1、创建作用域的方式
a)通过函数创建局部作用域
1、通过函数声明的方式创建
2、通过函数表达式创建:
匿名函数表达式和具名函数表达式
区别函数表达式和函数声明的方式就是看声明的第一个关键字是否是function开头
b)通过with、try...catch、let和const创建块作用域
值得提的是let和const定义的块作用域
let在声明变量时,会将变量附加在一个已经存在的块作用域上,一般是{}(隐式附加),let声明的变量是在js运行的时候才存在的。