重学 ES6

我心飞翔 分类:javascript

块级作用域变量

let word1 = 'hello'
const word2 = 'world'
 

let 用于声明变量 const 用于声明常量,常量一旦声明便无法更改

使用 let 和 const 声明的变量是有块级作用域(函数体,判断体,循环体等)

因此建议使用 es6 语法中 let const 来定义变量

模板字符串代替字符串拼接

const a = 'hello'
const b = 'world'

// in ES5
const c = a + ' ' + b 

// in ES6 used 模板字符串
const d = `${a} ${b}`
 

padStart()、padEnd()

新的字串填充方法,可以从start位置或是end位置,开始填充到指定数字长度,被填充的内容为第二个参数。

let astring = 'moment'
console.log(astring.padStart(10,'m'))
// 'mmmmmoment'

console.log('abc'.padStart(10, "foo"))
// "foofoofabc"

console.log('abc'.padEnd(10, "foo"))
// 'abcfoofoof'
 

解构赋值

// in ES5
let firstName = personalInformation.firstName
let lastName = personalInformation.lastName
let city = personalInformation.city

// in ES6 used 对象解构赋值
let { firstName: fn, lastName: ln, city: ct } = personalInformation
 

从 personalInformation 对象中读取 firstName , lastName , city 几个属性,并用 fn , ln , ct 几个别名作为解构赋值后新变量的名字,如果未声明别名,默认使用 firstName , lastName , city 作为解构后的变量名

// in ES6 used 数组解构赋值
let [firstName, lastName, city] = ['Dylan', 'Israel', 'Austin']
 

使用数组解构赋值时默认为按照数组顺序,逐一读取

加强循环

最早的数组遍历方式

var a = ["a", "b", "c"];
for(var index = 0;index < a.length;index++){
  console.log(a[index]);
}
 

自从ES5发布以后,可以用内建的forEach来遍历数组

var a = ["a", "b", "c"];
a.forEach(function(element) {
    console.log(element);
});
 

推荐在循环普通对象属性的时候,使用 for...in 在遍历数组的时候的时候使用 for...of

for...in循环出的是key ,for...of循环出的是value

for...of 不能循环普通的对象 需要通过和 Object.keys() 搭配使用

散布运算符 与 rest 参数

散布运算符

const t = [1, 2, 3, 4, 5]

const [first, second, ...rest] = t

console.log(first, second)  // 1, 2 is printed
console.log(rest)          // [3, 4 ,5] is printed
 

上面语法中的三个点 (...) 是散布运算符,其目标选定是特定变量中的整个值。

rest 参数

实际使用中经常遇到可变参数的情况,以定义函数实现计算传入所有参数的和为例.

使用arguments参数

**function** sumArgu () {
     **var** result **=** 0;
     **for** (**var** i **=** 0; i **<** arguments.length; i**++**) {
        result **+=** arguments[i];
    }
    **return** result
}
console.log(sumArgu(1,2,3));*//6*
 

使用rest参数

**function** sumRest (...m) {
	**var** total **=** 0; 
	**for**(**var** i **of** m){
	    total **+=** i;
	}
	**return** total;
}
console.log(sumRest(1,2,3));*//6*
 

上述两种方法看似差不多,但是操作的元素有本质的区别,其中arguments是一个类数组,本质是对象;而rest参数m,是真正的数组,可以正常调用数组的所有方法.所以在某些场景中,无需将arguments转为真正的数组,可以直接使用rest参数代替

includes()方法

Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。

[1, 2, 3].includes(3, 3); // false
 
[1, 2, 3].includes(3, -1); // true
 

第一个参数是要查找的元素

第二个参数表示搜索的起始位置,默认为 0 。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为 -4 ,但数组长度为 3 ),则会重置为从 0 开始。

[NaN].indexOf(NaN)

// -1

includes使用的是不一样的判断算法,就没有这个问题。

[NaN].includes(NaN)

// true
 

对比indexof方法

indexOf方法有两个缺点

一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于 -1 ,表达起来不够直观。

二是,它内部使用严格相当运算符( === )进行判断,这会导致对NaN的误判。

import & export 方法

ES6中export和import一般的用法有两种

  1. 命名导出(Named exports)
  2. 默认导出(Default exports)
// 导出单个特性
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}
// 导出列表
export { name1, name2, …, nameN };
// 重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };
// 解构导出并重命名
export const { name1, name2: bar } = o;
// 默认导出
export default expression;
export default function () { … } // also class, function*
export default function name1() { … } // also class, function*
export { name1 as default, … };
// 导出模块合集
export * from …; // does not set the default export
export * as name1 from …; // Draft ECMAScript® 2O21
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default } from …;

命名导出

//------ lib.js ------
const sqrt = Math.sqrt;
function square(x) {
return x * x;
}
function diag(x, y) {
return sqrt(square(x) + square(y));
}
export {sqrt, square, diag}
// 把export直接加到声明前面就可以省略{}
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ main.js ------
import { square, diag } from 'lib';				
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

无论怎样导出,引入的时候都需要{}

// 别名导入
import {speak as cowSpeak} from './cow.js'
import {speak as goatSpeak} from './goat.js'

别名导入使用 变量名 as 别名 导入对象

当从每个模块需要引入的方法很多的时候,这种写法就显得十分的繁琐、冗长,因此使用命名空间引入

import * as cow from './cow.js'
import * as goat from './goat.js'
cow.speak() // moo
goat.speak() // baa

默认导出

默认导出就不需要name了,但是一个js文件中只能有一个export default 但也可以导出多个方法。

export default {
speak () {
return 'moo'
},
eat () {
return 'cow eats'
},
drink () {
return 'cow drinks'
}
}

引入与命名空间引入类似

import cow from './default-cow.js'
import goat from './default-goat.js'
cow.speak() // moo
goat.speak() // baa

类 Class

// 在ES6中,我们终于有新的语法糖可以使用class了
class Animal{
constructor(name,color){
this.name = name
this.color = color
}
toString(){
console.log('name:'+this.name+',color:'+this.color)
}
}
const animal = new Animal('dog','white')
console.log(animal.toString()) // "name:dog,color:white"
// 以下为继承
class Cat extends Animal{
constructor(action){
// 记得这边要先super,才可以拿到父的资料
super('cat','white')
this.action = action
}
toString(){
console.log(super.toString())
}
}
const CCat = new Cat('Catch')
console.log(CCat.toString()) // "name:cat,color:white"
console.log(CCat instanceof Cat) // true
console.log(CCat instanceof Animal) // true

ES6 提供了 类似于面向对象的声明方法(实现封装继承,提供构造器)

promise & async & await

Promise

Promise 是一个对象,它代表了一个异步操作的最终完成或者失败。

本质上 Promise 是一个函数返回的对象,我们可以在它上面绑定回调函数,这样我们就不需要在一开始把回调函数作为参数传入这个函数了。

async await

在ES6为了要解决回调的问题,出现了Promise的then函数,但当逻辑很多时,,要链式多个then函数,会造成语意不清楚

new Promise((resolve,reject) => { resolve(42)}
.then(() => { do one})
.then(() => { do two})
.catch(() => {console.log(err)})
)

在ES8中,把非同步做得更方便,而这其实就是Promise与Generator的组合,而变成语法糖。

async function xxx(){
await do One
await do_Two
}

Map & Set

JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。

为了解决这个问题,最新的ES6规范引入了新的数据类型Map

Map

Map是一组键值对的结构,具有极快的查找速度。

var names = ['Michael', 'Bob', 'Tracy'];
var scores = [95, 75, 85];
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95

初始化Map需要一个二维数组,或者直接初始化一个空Map。

Map具有以下方法:

var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined

由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉:

var m = new Map();
m.set('Adam', 67);
m.set('Adam', 88);
m.get('Adam'); // 88

Set

Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。

要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set:

var s1 = new Set(); // 空Setvar s2 = new Set([1, 2, 3]); // 含1, 2, 3

重复元素在Set中自动被过滤:

var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}

数组中数字3和字符串'3'是不同的元素。

Set具有以下方法:

var s = new Set([1, 2, 3]);
// add(key)方法可以添加元素到Set中可以重复添加,但不会有效果:
s.add(4);
s; // Set {1, 2, 3, 4}
s.add(4);
s; // Set {1, 2, 3, 4}
//delete(key)方法可以删除元素:
s.delete(3);
s;// Set{1, 2, 4}

回复

我来回复
  • 暂无回复内容