全局作用域为程序的最外层作用域,一直存在
函数作用域只有函数被定义时才会创建,包含在父级函数作用域 / 全局作用域内。
花括号内 {…} 的区域就是块级作用域区域。使用 let 和 const 可以创建块级作用域
当可执行代码内部访问变量时,会先查找本地作用域,如果找到目标变量即返回,否则会去父级作用域继续查找…一直找到全局作用域。我们把这种作用域的嵌套机制,称为 作用域链。
在 ES6 中,使用 let 命令定义变量,使用 const 命令定义常量。
let所声明的变量会创建自己的块级作用域;var定义的变量,作用域为定义它的函数,或者全局,并且是能自动往全局对象 window 上绑定属性的。
面试题:
var result = [];
(function () {
for (var i = 0; i < 5; i++) {
result.push(function () {
console.log(i);
});
}
})();
result.forEach(function (item) {
item()
});
// => 打印出五个 5
var result = [];
(function () {
for (let i = 0; i < 5; i++) {
result.push(function ( ) {
console.log(i);
});
}
})();
result.forEach(function (item) {
item()
}); // => 0,1,2,3,4
// let会创建块级作用域,上面的代码会被编译成如下代码
"use strict";
var result = [];
(function () {
var _loop = function _loop(i) {
result.push(function () {
console.log(i);
});
};
for (var i = 0; i < 5; i++) {
_loop(i);
}
})();
result.forEach(function (item) {
item();
});
let定义的变量不会进行变量声明提升操作,也就是说在访问该变量之前必须要先定义; var定义的变量存在变量声明提升,因此在变量定义前就能访问到变量,值是 undefined。
console.log(a); // undefined
var a = 1;
console.log(b); // Uncaught ReferenceError: Cannot access 'b' before initialization
let b = 2;
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError: tmp is not defined
let tmp;
}
同样,这个特性也是被浏览器内部的 JS 执行引擎支持和实现的,babel 无法支持这种特性的编译,只能简单的将 let 编译成 var。但是有意思的是,由于 let 在 if 块中是可以构建自己的独立作用域的,babel 将 tmp 这个变量换了个名字来模拟实现块级作用域的创建:
"use strict";
var tmp = 123;
if (true) {
_tmp = 'abc';
var _tmp;
}
let定义的变量,一旦定义便不允许被重新定义;var定义的变量,可以被重新定义。一般使用该方法来解决模块名污染全局作用域的问题
// module1.js
(function () {
var a = 1;
console.log(a);
})();
当圆括号出现在匿名函数的末尾想要调用函数时,它会默认将函数当成是函数声明。
当圆括号包裹函数时,它会默认将函数作为表达式去解析,而不是函数声明。