一、作用域
概念:代码中的某个成员能够起作用的范围
分类:
- 全局作用域
- 函数作用域
- 块级作用域(ES2015加入,{}一对大括号代表一个块级作用域):
二、变量声明
1、var
-
在块内定义的成员,外部可访问,对于复杂的代码这是非常不利且不安全的
-
存在变量提升,在声明之前打印的话结果是undefined
if(true) {
var name = 'Judy'
}
console.log(name) // Judy
2、let
-
声明的变量只能在代码块内使用,外部不能使用,外部如果使用则会报错
-
另外let声明的变量不会进行变量提升,因此要先声明,再使用。日常代码写作中也建议如此书写。
if(true) {
let name = 'Judy'
}
console.log(name) // ReferenceError: name is not defined
3、使用场景:
-
声明for循环的计数器
当传统的循环出现循环嵌套必须声明不同的变量,但是let关键字可以不需要重新声明,虽然如此,但是仍然建议声明一个新的变量增强可读性。
for(var i = 0; i < 3; i++) {
for (var i = 0; i < 3; i++){
console.log(i)
}
}
// 0 1 2
for(let i = 0; i < 3; i++) {
for (let i = 0; i < 3; i++){
console.log(i)
}
}
// 0 1 2 0 1 2 0 1 2
-
循环注册事件(闭包的经典使用场景,后续的文章中会有对于循环注册事件的功能优化部分,写好后会将链接补充过来)
在事件的处理过程中需要访问循环的计数器,直接用var声明变量作为计数器得不到我们想要的结果,之前我们通常是借助函数作用域摆脱全局作用域的影响,但是直接用let声明就可以写的很简单,它的内部实现机制是一样的。
// 模拟函数点击事件
// var
const elements = [{}, {}, {}];
const len = elements.length;
for(var i = 0; i < len; i++) {
elements[i].onclick = function (params) {
console.log(i);
}
}
elements[0].onclick(); // 3
elements[1].onclick(); // 3
elements[2].onclick(); // 3
// 写法一: 借助函数作用域避免全局作用域带来的副作用
const elements = [{}, {}, {}];
const len = elements.length;
for(var i = 0; i < len; i++) {
(function(xc) {
elements[xc].onclick = function (params) {
console.log(xc);
}
})(i)
}
elements[0].onclick(); // 0
elements[1].onclick(); // 1
elements[2].onclick(); // 2
// 写法二
const elements = [{}, {}, {}];
const len = elements.length;
for(var i = 0; i < len; i++) {
elements[i].onclick = (function(xc) {
return function () {
console.log(xc);
}
})(i)
}
elements[0].onclick(); // 0
elements[1].onclick(); // 1
elements[2].onclick(); // 2
// let
const elements = [{}, {}, {}];
const len = elements.length;
for(let i = 0; i < len; i++) {
elements[i].onclick = function (params) {
console.log(i);
}
}
elements[0].onclick(); // 0
elements[1].onclick(); // 1
elements[2].onclick(); // 2
4、说明
for循环有两层嵌套的作用域,外层是for循环本身的作用域,内层是循环体的作用域
for (let i = 0; i < 3; i ++) {
let i = 'Judy'
console.log(i)
}
// Judy Judy Judy
可以这样理解
{
// 外层作用域
for (let i = 0; i < 3; i ++) {
// 内层作用域,如果内层找不到i,就会到外层去找,相当于作用域链
let i = 'Judy'
console.log(i)
}
}
备注:如有问题,请给出建议,谢谢