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
//JLE
var 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
{
//0
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击')
})
}
{
//1
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击')
})
}
{
//2
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击')
})
}
{
//3
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击')
})
}
{
//4
btns[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 = 0
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击')
})
}
{
i = 1
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击')
})
}
{
i = 2
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击')
})
}
{
i = 3
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击')
})
}
{
i = 4
btns[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()