目录:
一、ECMAScript 和 JavaScript 的关系
二、ES6 与 ECMAScript 2015 的关系
三、Let
四、const
五、const & let
六、作用域
七、解构赋值
一、ECMAScript 和 JavaScript 的关系
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。
二、ES6 与 ECMAScript 2015 的关系
1.标准委员会制定的标准是,每年的6月份正式发布一次,作为当年的正式版本。接下来的时间,就在这个版本的基础上做改动,直到下一年的6月份,草案就自然变成了新一年的版本。这样一来,就不需要以前的版本号了,只要用年份标记就可以了。
2.ES6 的第一个版本,在2015年6月发布,正式名称是《ECMAScript 2015标准》,简称 ES2015。
3.ES6 既是一个历史名词,也是一个泛指,含义是5.1版以后的 JavaScript 的下一代标准,涵盖了ES2015、ES2016、ES2017等等。
三、Let
特点
1.没有预解析,不存在变量的提升,所以在一个代码块内,先使用let定义的变量再定义的话会报错;
2.在同一个作用域里,不能重复定义变量
`let a = 5;{ let a = 10;}` //是正确的,因为是两个不同的作用域;
3.for 循环中,循环语句部分是一个父作用域,而循环体内部是一个单独的子作用域;
则:
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i); // 输出三次 abc
}
四、const
特点
1.const定义的变量不能修改;
2.const定义完变量,必须马上赋值,只能这么定义`const csdn = ‘aa’,不能分开;`
3.const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了,即对象和数组里面的属性可以修改。
4.若想要使得对象不得修改,使用 Object.freeze(obj) 即可 ;
<script >
// const 定义的变量不能修改,但是对象的属性可以修改
const arr1= ['a','b'];
arr.push('c');
console.log(arr1);
// arr2 不能修改,
const arr2= Object.freeze(['a','b']);
console.log(arr2);
arr.push('c'); // 错误,已经被冻结了,object is not extensible
console.log(arr);
</script>
五、const & let
注意:
如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域,凡是在声明之前就使用这些变量,就会报错,在语法上,这种情况称为“暂时性死区”(temporal dead zone,简称 TDZ)。
则:
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
六、作用域
ES5 只有全局作用域和函数作用域,没有块级作用域;
ES6 新增块级作用域,通过let 来实现;
块级作用域与函数声明
1.允许在块级作用域内声明函数。
2.函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
3.同时,函数声明还会提升到所在的块级作用域的头部。
注意,上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。
应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
七、解构赋值
1.ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。
2.只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。
https://www.cnblogs.com/zczhangcui/p/6502836.html
3.非常有用,特别是在左数据交互的时候
4.注意两边的结构格式要保持一致 :
let [a,b,c] = [1,3,6];
console.log(a,c,b); //1,6,3
json :
let {a,b,c} = {
a:1, b:3,c:6
};
console.log(a,c,b) //1,6,3
数组解构
1.如果解构不成功,变量的值就等于undefined。
2.等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功
3.解构赋值允许指定默认值,,如果一个数组成员不严格等于undefined,默认值就不会生效。
let [x = 1] = [undefined];
x // 1 生效
let [x = 1] = [null];
x // null 失效
对象的解构赋值
- 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
baz // undefined 未定义
// 以上的代码实际上是下面形式的简写
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
// 则: foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。
let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined
2.声明和赋值不同时时:
let命令下面一行的圆括号是必须的,否则会报错。因为解析器会将起首的大括号,理解成一个代码块,而不是赋值语句。
let foo;
({foo} = {foo: 1}); // 成功
3.对象也可以指定默认值,与数组解构同
还有字符串的解构赋值、数值和布尔值的解构赋值、函数参数的解构赋值,这里就不多说了
解构的用途
(1)交换变量的值
let x = 1;
let y = 2;
[x, y] = [y, x];
上面代码交换变量x和y的值,这样的写法不仅简洁,而且易读,语义非常清晰。
(2)从函数返回多个值
函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。
// 返回一个数组
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 返回一个对象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
(3)函数参数的定义
解构赋值可以方便地将一组参数与变量名对应起来。
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
(4)提取JSON数据
解构赋值对提取JSON对象中的数据,尤其有用。
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number); // 42, "OK", [867, 5309]
上面代码可以快速提取 JSON 数据的值。
(5)函数参数的默认值
jQ
uery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
}) {
// ... do stuff
};
指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || ‘default foo’;这样的语句。
(6)遍历Map结构
任何部署了Iterator接口的对象,都可以用for…of循环遍历。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便。
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
如果只想获取键名,或者只想获取键值,可以写成下面这样。
// 获取键名
for (let [key] of map) {
// ...
}
// 获取键值
for (let [,value] of map) {
// ...
}
(7)输入模块的指定方法
加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。
const { SourceMapConsumer, SourceNode } = require(“source-map”);
圆括号问题
以下三种解构赋值不得使用圆括号。
(1)变量声明语句中,模式不能带有圆括号。
// 全部报错
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
(2)函数参数中,模式不能带有圆括号。
函数参数也属于变量声明,因此不能带有圆括号。
// 报错
function f([(z)]) { return z; }
(3)赋值语句中,不能将整个模式,或嵌套模式中的一层,放在圆括号之中。
// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];
可以使用圆括号的情况
可以使用圆括号的情况只有一种:赋值语句的非模式部分。
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确