- ES5之前因为if和for都没有块级作用域的概念,只有function有作用域,所以很多时候都必须借助于function的作用域来解决应用外面变量的问题
- ES6中加入了let,let有if和for的块级作用域
1. 变量作用域:变量在什么范围内是可用
大括号是一个代码块
{
var name = 'hammer';
console.log(name);
}
console.log(name);
- 代码块内定义的变量在代码块外也能使用
- 代码块对于var定义的变量来说不是作用域的限制,即没有块级作用域
2. 没有块级作用域引起的问题:if的块级
var func;
if (true) {
var name = 'hammer';
func = function () {
console.log(name);
}
}
name = 'sister'
func();
func()
调用打印的是sisterfunc()
调用是为了打印if块内定义的那个name也就是hammer,但是在func()
调用之前name被改掉了
3. 没有块级作用域引起的问题:for的块级
经典例子:五个按钮,点击哪个按钮就打印“按钮几被点击了”
body标签内包含五个button
<button>按钮0</button>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
下面是三种不同的js写法
第一种写法:ES5中没有使用闭包(错误的)
var btns = document.getElementsByTagName('button');
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击');
})
}
- 这样写不管点击哪个按钮,显示的都是第5个按钮被点击
addEventListener
里面的函数被执行的时候,i已经被改掉了,js异步执行
第二种写法:ES5中使用闭包
var btns = document.getElementsByTagName('button');
for (var i = 0; i < btns.length; i++) {
(function (num) {
btns[i].addEventListener('click', function () {
console.log('第' + num + '个按钮被点击');
})
})(i)
}
- 闭包可以解决问题,因为函数是一个作用域
- 但是闭包的写法不利于代码阅读,看上去很复杂
(function(){/* code */})();
这是立即调用函数的一种写法,里面的函数表达式会被立即调用- 关于函数作用域
var name = 'hammer';
function abc(name) {
console.log(name);
}
name = 'sister';
abc('aaa');
// 打印的是aaa,传入的aaa是输入abc函数的作用域的name,函数优先调用属于自己name,外面name更改不会影响函数里面,这也是形参存在的意义
// 所以上面的闭包,内部的函数有自己num,传入i之后,外面i被改掉不会对里面有影响,相当于那里有五个函数
第三种写法:ES6中的let
const btns = document.getElementsByTagName('button')
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击');
})
}
- 最好的实现方式
总而言之,ES5中的var是没有块级作用域的(if/for),ES6中的let是有块级作用域的(if/for)
补充:const的使用
建议在ES6开发中,优先使用const,只有需要改变某一个标识符的时候才使用let
注意一:一旦给const修饰的标识符被赋值之后不能修改
错误示范:
const name = 'hammer';
name = 'sister';
注意二:使用const定义标识符必须进行赋值
错误示范:
const name;
注意三:常量的含义是指向的对象不能修改,但是可以改变对象内部的属性
const obj = {
name: 'hammer',
age: 20,
height: 1.81
}
console.log(obj);
obj.name = 'sister';
obj.age = 40;
obj.height = 2.10;
console.log(obj);