ES6简介
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
一、ES6之let和const的使用
1.1块级作用域
在ES5之前,不存在块级作用域,在编程的时候很多时候会带来很多的不便,ES6新增了块级作用域,补足了这方面的缺陷。
块级声明指的是该声明的变量无法被代码块外部访问。块作用域,又被称为词法作用域(lexical scopes),可以在如下的条件下创建:
- 函数内部
- 在代码块(即 { })内部
块级作用域是很多类C语言的工作机制,ECMAScript 6 引入块级声明的目的是增强 JavaScript 的灵活性,同时又能与其它编程语言保持一致。
1.2 let声明
使用let声明变量的语法和使用var声明的语法是一样的。但是let声明的变量的作用域会限制在当前的代码块中。这是let与var的最大区别。
<script type="text/javascript">
/*** var 和 ES6 let对比 ****/
{
var a = 10;
let b = 20;
}
console.log(a);
// 因为let声明后具有块级作用域 出了代码块后就访问不到 说报错
console.log(b);
</script>
<script type="text/javascript">
//在for循环中的使用
for (var i = 0; i < 5; i++) {
}
console.log(i);
for (let j = 0; j < 5; j++) {
}
//这里 j 也是存在代码块中, 这里会报错
console.log(j);
</script>
<script type="text/javascript">
//用var 声明的时候 有变量提升的特性
console.log(c);
var c = 'c';
//使用let 不会有变量提升
console.log(d);
let d = 'd';
</script>
<script type="text/javascript">
var e = "e";
if (true) {
e = "ee";
//在代码块中,只要存在let命令,它声明的所有变量都会绑定在它身上。
let e = "小王";
console.log(e);
}
</script>
总之在代码块内,使用变量之前,一定要用let声明好。
如果let在使用变量之后声明的话,我们称为:"暂时性死区" (temporary dead zone,简称:TDZ)。
<script type="text/javascript">
if (true) {
//TDZ 开始
d = "d";
console.log(d)
//TDZ 结束
let d = "dd";
console.log(d);
}
</script>
let不允许在同一作用域中声明重复的变量
<script type="text/javascript">
(function () {
let a = "a";
//let a = "b";
})();
(function () {
let a = "a";
//var a = "b";
})();
(function (arg) {
//let arg = "a";
})();
(function (arg) {
{
//自己在独立的一个块级里,就不会和形参的arg有冲突了。
let arg = "a";
}
})();
</script>
关于全局变量,在var声明的情况下,全局变量就等同于全局对象的属性,用ES6的let声明全局变量则不会。
<script type="text/javascript">
var str = 33;
console.log(window.str); //33
let str2 = "bcd";
console.log(window.str2); //undefined
console.log(str2); //bcd
</script>
利用let解决一个比较经典的问题
<input type="button" value="按钮1" id="button1" />
<input type="button" value="按钮2" id="button2" />
<input type="button" value="按钮3" id="button3" />
<script type="text/javascript">
for (var z = 1; z < 4; z++) {
var button = document.getElementById('button' + z);
button.addEventListener('click', function () {
alert('button' + (z)); //每次打印结果 都是 button4
});
}
//利用函数立即执行、形成闭包。每次保存z的值 这样就可以实现我们想要的结果
for (var z = 1; z < 4; z++) {
var button = document.getElementById('button' + z);
//每次循环把i存储起来
(function (z) {
button.addEventListener('click', function () {
alert('button' + (z));
});
})(z);
}
//更简单的解决办法,形成块级作用域,使用let
for (let z = 1; z < 4; z++) {
var button = document.getElementById('button' + z);
button.addEventListener('click', function () {
alert('button' + (z)); //每次打印结果 都是 button4
});
}
</script>
1.3 const声明
在 ES6 使用const来声明的变量称之为常量。这意味着它们不能再次被赋值。由于这个原因,所有的 const 声明的变量都必须在声明处初始化。
const声明的常量和let变量一样也是具有块级作用域的特性,一样不支持变量(常量)提升,一样存在"TDZ"。
const命令用来声明常量,常量一旦声明,就无法改变。
const命令用来声明常量,一定要初始化。
<script type="text/javascript">
const PI = "3.1415..";
console.log(PI);
PI = "能修改吗?"; // 报错,常量不能修改
console.log(PI);
</script>
注意:针对于引用类型,修改值就是修改变量指针的指向。指向不同的对象实例
<script type="text/javascript">
const OBJ = {};
//OBJ = { age : 18 }; 不可以,这样相当于修改了对象的指针指向
OBJ.name = "小雪"; //可以,这个没有修改对象的指针指向,而是修改内部的属性值
console.log(OBJ);
//我们可以使用Object.freeze()冻结这个对象,从而达到不能操作对象的属性
Object.freeze(OBJ);
OBJ.age = 18;
OBJ.name = "小虹";
console.log(OBJ);
</script>
二、变量的解构
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)
以前,为变量赋值,只能直接指定值。
let a = 1;
let b = 2;
let c = 3;
ES6 允许写成下面这样。
let [a, b, c] = [1, 2, 3];
上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。
2.1 数组的解构
只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。
let [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo) // 1
console.log(bar) // 2
console.log(baz) // 3
let [ , , third] = ["foo", "bar", "baz"];
console.log(third) // "baz"
let [x, , y] = [1, 2, 3];
console.log(x) // 1
console.log(y) // 3
let [head, ...tail] = [1, 2, 3, 4];
console.log(head) // 1
console.log(tail) // [2, 3, 4]
let [x, y, ...z] = ['a'];
console.log(x) // "a"
console.log(y) // undefined
console.log(z) // []
如果解构不成功,变量的值就等于undefined。
let [foo] = [];
let [bar, foo] = [1];
以上两种情况都属于解构不成功,foo的值都会等于undefined。
另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
let [x, y] = [1, 2, 3];
console.log(x) // 1
conole.log(y) // 2
let [a, [b], d] = [1, [2, 3], 4];
console.log(a) // 1
console.log(b) // 2
console.log(d) // 4
上面两个例子,都属于不完全解构,但是可以成功。
如果等号的右边不是可遍历的结构,那么将会报错。
// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
上面的语句都会报错,因为等号右边的值,要么转为对象以后不具备 Iterator 接口(前五个表达式),要么本身就不具备 Iterator 接口(最后一个表达式)。
2.2 对象的解构
解构不仅可以用于数组,还可以用于对象。
let { foo, bar } = { foo: "aaa", bar: "bbb" };
console.log(foo) // "aaa"
console.log(bar) // "bbb"
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let { bar, foo } = { foo: "aaa", bar: "bbb" };
console.log(foo) // "aaa"
console.log(bar) // "bbb"
let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
上面代码的第一个例子,等号左边的两个变量的次序,与等号右边两个同名属性的次序不一致,但是对取值完全没有影响。第二个例子的变量没有对应的同名属性,导致取不到值,最后等于undefined。
如果变量名与属性名不一致,必须写成下面这样。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
console.log(baz) // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
console.log(f) // 'hello'
console.log(l) // 'world'
这实际上说明,对象的解构赋值是下面形式的简写)。
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
let { foo: baz } = { foo: "aaa", bar: "bbb" };
console.log(baz) // "aaa"
console.log(foo) // error: foo is not defined
上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。
如果要将一个已经声明的变量用于解构赋值,必须非常小心。
// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error
上面代码的写法会报错,因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
// 正确的写法
let x;
({x} = {x: 1});
2.3 字符串的解构
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = 'hello';
console.log(a) // "h"
cnosole.log(b) // "e"
console.log(c) // "l"
console.log(d) // "l"
console.log(e) // "o"
类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
let {length : len} = 'hello';
console.log(len) // 5
三、模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
// 普通字符串
`In JavaScript '\n' is a line-feed.`
// 多行字符串
`In JavaScript this is
not legal.`
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入变量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
网友评论