本文关于ES6的讲解比较简单,如有兴趣还请阅读阮一峰大佬的ECMAScript
6入门。
第十章 ES6与模块化
1. 常用语法知识
let/const
在ES5中,使用var来声明一个变量。在ES6中,新的变量声明方式带来了一些不一样的特性,其中最重要的就是具备了块级作用域并且不再有变量提升(这很重要)。
下面通过一个简单的例子来说明。
// ES5
console.log(a); // undefined
var a = 20;
// ES6
console.log(a); // Uncaught ReferenceError: a is not defined
let a = 20;
ES5存在变量提升,其实ES6也存在,但是并不会给这个变量赋值为undefined。也就是说,虽然声明提前了,但是该变量并没有任何引用,所以上例才会报ReferenceError。
由于不会默认赋值undefined,加上let/const存在自己的作用于,因此会出现一个叫作暂时性死区的现象。
因此在编写ES6代码中要注意,尽量将申明主动放置在代码的前面。
要想使用ES6,就需要全面使用let/const来替换之前非常常用的var,那么什么时候用let,什么时候用const呢?
一般来说,声明一个引用可以被改变的变量时用let,声明一个引用不能被改变的变量时用const。
例如:
let a = 20;
a = 30;
a = 40;
console.log(a); // 40
const PI = 3.1415;
const MAX_LENGTH = 100;
PI = 3; // Uncaught TypeError: Assignment to constant variable
除此之外,当声明一个引用类型的数据时,也会使用const。尽管可能会改变该数据的值,但是必须保持它的引用不变。
const a = [];
a.push(1);
console.log(a); // [1]
const b = {};
b.max = 20;
b.min = 0;
console.log(b); // {max: 20, min: 0}
箭头函数
与function相比,箭头函数是一个用起来更加舒服的语法。
// ES5
var fn = function (a, b) {
return a + b;
}
// ES6
const fn = (a, b) => a + b;
// ES5
var foo = function () {
var a = 20;
var b = 30;
return a + b;
}
// ES6
const foo = () => {
const a = 20;
const b = 30;
return a + b;
}
需要注意,箭头函数只能替换函数表达式,即使用var/let/const声明的函数。而直接使用function声明的函数是不能使用箭头函数替换的。
箭头函数中的this,就是声明函数时所处上下文中的this,它不会被其他方式所改变。
// ES5
var name = 'Tom';
var getName = function () {
console.log(this.name);
}
var person = {
name: 'Alex',
getName: getName
}
var other = {
name: 'Joe'
}
getName(); // Tom,默认绑定,this指向window
person.getName(); // Alex,由person调用,this指向person
getName.call(other); // Joe,显示绑定,通过call使this指向other
// ES6
var name = 'Tom';
var getName = () => {
console.log(this.name);
}
var person = {
name: 'Alex',
getName: getName
}
var other = {
name: 'Joe'
}
getName(); // Tom
person.getName(); // Tom
getName.call(other); // Tom
除此之外,arguments还有一个需要大家注意的地方,即在箭头函数中,没有arguments对象。
// ES5
var add = function (a, b) {
console.log(arguments);
return a + b;
}
add(1, 2); // Arguments(2) [1, 2, callee: f, Symbol(Symbol.iterator): f]
// ES6
var add = (a, b) => {
console.log(arguments);
return a + b;
}
add(1, 2); // Uncaught ReferenceError: arguments is not defined
2. 模板字符串
模板字符串是为了解决传统字符串拼接不便利而出现的。
// ES5
var a = 20;
var b = 30;
var string = a + "+" + b + "=" + (a + b);
// ES6
const a = 20;
const b = 30;
const string = `${a} + ${b} = ${a + b}`;
模板字符串使用反引号`将整个字符串包裹起来,变量或表达式则使用${}来包裹。
除了能够在字符串中嵌入变量,还可以用来定义多行字符串,其中所有的空格、缩进、换行都会被保留下来。
var elemString = `<div>
<p>I like brother black.</p>
<p>I am sorry to lose you. ${word}</p>
</div>`
如果是用传统的+拼接这段字符串,则会非常麻烦(各种转义)。
${}中可以放入一个变量、表达式,甚至一个函数。
const hello = 'hello';
let message = `${hello}, world!`;
const a = 20;
const b = 30;
let result = `the result is: ${a + b}`;
let fn = () => {
const result = `you are the best`;
return result;
}
let str = `he said: ${fn()}`;
3. 解析结构(解构赋值)
解构赋值是一种从对象或者数组中取得值的一种全新的写法,只需通过一个简单的例子就能立刻明白是怎么回事(实际开发用的很多)。
// 假设存在这样一个json数据
var tom = {
name: 'Tom',
age: 20,
gender: 1,
job: 'student'
}
// ES5
var name = tom.name;
var age = tom.age;
var gender = tom.gender;
var job = tom.job;
// ES6
const {name, age, gender, job} = tom;
可以看到ES6解构赋值比传统赋值方便了很多,我们还可以给变量指定默认值或者重命名。
const {name = 'Jake', stature = '170'} = tom;
console.log(name); // Tom,如果数据中找到name,则变量的值与数据中相等
console.log(stature); // 170,如果数据中找不到stature,则使用默认值
const {gender: t, job} = tom;
console.log(gender); // Uncaught ReferenceError: gender is not defined
console.log(t); // 1,重命名后gender将无法访问
我们还可以利用解构赋值获取嵌套数据中的值。
const peoples = {
counts: 100,
detail: {
tom: {
name: 'Tom',
age: 20,
gender: 1,
job: 'student'
}
}
}
// 获取tom
const {detail: {tom}} = peoples;
// 获取tom的age与gender
const {detail: {tom: {age, gender}}} = peoples;
此外,数组也有自己的解构赋值。当然,写法与对象的解构赋值略有不同。
const arr = [1, 2, 3];
const [a, b, c] = arr;
// 等价于
const a = arr[0];
const b = arr[1];
const c = arr[2];
与对象不同的是,数组中变量和值得关系与索引是一一对应的,这是一个有序的对应关系,而对象则是根据键值对一一对应的,这是一个无序的对应关系系。因此在实践中,对象的解构赋值使用的更加频繁与便利。
4. 展开运算符
在ES6中,使用...来表示展开运算符,它可以展开数组/对象。
// 首先声明一个数组
const arr1 = [1, 2, 3];
// 其次声明另一个数组,我们希望新数组中包含数组arr1的所有元素
const arr2 = [...arr1, 4, 5, 6];
console.log(arr2); // [1, 2, 3, 4, 5, 6]
当然,展开对象也可以得到类似的结果。
const object1 = {
a: 1,
b: 2,
c: 3
}
const object2 = {
...object1,
d: 4,
e: 5,
f: 6
}
console.log(object2); {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}
在解构赋值中,也常常使用展开运算符。
const tom = {
name: 'Tom',
age: 20,
gender: 1,
job: 'student'
}
const {name, ...others} = tom;
console.log(others); // {age: 20, gender: 1, job: 'student'}
展开运算符还可以运用在函数参数中,放置于函数参数的最后一个参数(且只能放置在最后,具体原因参考阮一峰ECMAScript6入门),表示不定参。
const add = (a, b, ...more) => {
return more.reduce((m, n) => m + n) + a + n;
}
console.log(add(1, 23, 1, 2, 3, 4, 5)); // 39
5. Promise
同步与异步
同步是指当发起一个请求时,如果未得到请求结果,代码将会等待,直到结果出来,才会执行后面的代码。
异步是指当发起一个请求时,不会等待请求结果,而是直接继续执行后面的代码。
我们使用Promise模拟一个发起请求的函数,该函数在执行后,会在1s之后返回数值30。
function fn () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(30)
}, 1000)
})
}
// 在该函数的基础上,可以使用async/await语法来模拟同步的效果
var foo = async function () {
var t = await fn();
console.log(t);
console.log('next code');
}
foo(); // 1s之后输出30,next code
而异步效果则会有不同的输出结果。
var foo = function () {
fn().then(function (resp) {
console.log(resp);
});
console.log('next code');
}
foo(); // next code,1s之后输出30
以上是我对JavaScript核心技术开发解密第十章(上)的读书笔记,码字不易,请尊重作者版权,转载注明出处。
By BeLLESS 2018.8.5 15:18
网友评论