js中的作用域层面:函数作用域 -> 块级作用域 -> 作用域链
1)函数作用域:早期,js中只有函数有作用域,函数用来划分全局和局部作用域。
function f(){
var a = 1;
console.log(a) // 1
}
f()
console.log(a) //undefined
2)块级作用域:es6之后,增加了块级语句{}的作用域,例如 if() { ... }、for() {...}、while() { ... } 、
(也就是说 现在除了函数的{}外,所有{}语句块都可以有作用域,块级作用域看成是函数
作用域的升级)
var和let的区别:
1)let 会创建块级作用域,var只在函数{}才有作用域;
2)var有声明提升,let没有;
3)var可以重复声明 语法可以通过,let不行;
4)var声明的全局变量会挂在到window上,而let不是;
var fns = [];
for (var i = 1; i < 4; i++) {
fns.push(function () {
console.log(i);
});
}
console.log(fns); // [func, func, func]
// 函数执行时 for已经结束 此时的i是循环的最大值 4
fns[1](); // 4
var fns = [];
for (let i = 1; i < 4; i++) {
// let 会绑定作用域,将i限定在{}里面用,每次循环时 创建的i 都有属于自己的{}
// 相当于有3个 {i:1 function () {log(i)}} {i:2 function () {log(i)}} {i:3}
// 函数每次调用时 要使用所属的{i},也就是说let能够保留循环时i的值
fns.push(function () {
console.log(i);
});
}
console.log(fns); // [func, func, func]
fns[1](); // 2
// 全局变量a 它属于全局变量对象window,它的作用域就是全局,记作:window(a)
// 函数function体内的变量b,它属于激活对象fAO,它的作用域是fAO,记作:fAO(b)
// 这里要注意,fAO是函数调用时动态创建出来,并添加到function作用域链的头部,也就说:
// fAO(b) => f.fAO(b) => [根]window(a,f).fAO(b)[头]
var a = 1; // window(a)
function f () {
// window(a,f).fAO(a,b)
var b = 2;
var a = 2;
console.log(b); // 2
console.log(a); // 2
}
f();
// 组成变量作用域其实是一个对象链。如果要使用某个变量 则沿着作用域链头部查找,如果找到则返回 找不到继续往下 直到根部 - 变量名的解析
// 作用域链的机制:变量由内向外 查找
内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境的任何变量和函数。