1. let / var
- 事实上var的设计可以看成JavaScript语言设计上的错误. 但是这种错误多半不能修复和移除, 以为需要向后兼容.
- 大概十年前, Brendan Eich就决定修复这个问题, 于是他添加了一个新的关键字: let.
- 我们可以将let看成更完美的var
- 块级作用域
- JS中使用var来声明一个变量时, 变量的作用域主要是和函数的定义有关.
- 针对于其他块定义来说是没有作用域的,比如if/for等,这在我们开发中往往会引起一些问题。
1.1 ES6之前 没有块级作用域的缺陷
变量作用域:变量在上面范围内是可用的
没有块级作用域引起的问题:
{var name = 'JLE'console.log(name)}console.log(name)//输出//JLE//JLEvar func;if (true) {var name = 'WHO'func = function () {console.log(name)}func()}func()//输出//WHO//WHO
上面就是变量 和 if 没有块级作用域的问题,可能会觉得问题不是很大。
下面再来看一个 for 没有块级作用域的问题:
<button type="button">按钮1</button><button type="button">按钮2</button><button type="button">按钮3</button><button type="button">按钮4</button><button type="button">按钮5</button><script type="text/javascript">var btns = document.getElementsByTagName('button');for (var i = 0; i < btns.length; i ++ ) {btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}</script>
这段代码本来是点击按钮,控制台输出对应编号的按钮被点击,结果不论点击哪个按钮都是显示 “第5个按钮被点击”
通过for 循环给5个按钮绑定事件监听,由于 i 没有作用域的概念,相当于 i 是全局变量,Java中的 类的static 变量,大家共享一个 i。当 for循环结束到时候, i = 5,所以不论点击哪个按钮都是显示 “第5个按钮被点击”。
for 代码演示,当 i 没有块级作用域时,也就是 变量 i 在全局都是可用的。当 i 改变时,5个事件监听里面的 i 都会改变
var i = 5{//0btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}{//1btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}{//2btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}{//3btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}{//4btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}
在ES5的时候,想要完成上面的操作,由于 变量 是没有块级作用域,但是 函数有块级作用域,所以使用 闭包来完成上述的操作
为什么闭包可以解决问题:函数是一个作用域
通过自增量 i 作为函数的实参 传入到函数中,并绑定函数,由于 函数中有块级作用域,当 i 再发生改变时,函数内部的形参不会跟着改变。
for (var i = 0; i < btns.length; i ++ ) {(function (num) {btns[i].addEventListener('click', function () {console.log('第' + num + '个按钮被点击')})})(i)}
再看一个简单的小栗子:这里给函数传入 参数 name 的是 James,即使外部 name 改为 Kobe,也不会影响函数内部,
var name = 'WHO'function abc(name) {console.log(name)}name = 'Kobe'abc('James')
1.2 ES6:let 解决块级作用域问题
在 ES6 新增的 let 为了解决块级作用域的问题: 不需要使用闭包的繁琐写法
const btns = document.getElementsByTagName('button');for (let i = 0; i < btns.length; i ++ ) {btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}
for 代码演示如下:每个监听函数都有自己一个独立的 i,当外部的 i 发生改变时,不影响函数内部的 i
let i = 5{i = 0btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}{i = 1btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}{i = 2btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}{i = 3btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}{i = 4btns[i].addEventListener('click', function () {console.log('第' + i + '个按钮被点击')})}
2. const
const 关键字
- 在很多语言中已经存在,比如 C/C++中,主要的作用是将某个变量修饰为常量。
- 在 JavaScript中也是如此,使用 const修饰的标识符为常量,不可以再次赋值
什么时候使用 const呢?
- 当我们修饰的标识符不会被再次赋值时,就可以使用 const 来保证数据的安全性
在 ES6开发中,优先使用 const,只有需要改变一个标识符的时候才使用 let
- const 的注意:
const a = 20;a = 30; //错误:不可以修改
常量的含义是指向对象不能修改,但是可以修改对象内部的属性const name; //错误:const修饰的标识符必须赋值
**3. 对象字面量的增强写法
在 ES6 中,对对象字面量进行了很多增强
属性初始化简写和方法简写:
//1.属性的增强写法let name = 'JLE';let age = 18;let height = 1.8;//ES6之前写法const obj1 = {name: name,age: age,height: height}console.log(obj1);//ES6之后const obj2 = {name, age, height}console.log(obj2)
//2.方法的简写//ES6之前写法const obj1 = {test: function () {console.log('obj1的test函数')}}obj1.test()//ES6之后let obj2 = {test () {console.log('obj2的test函数')}}obj2.test()
