Es6使用详解

前言

前端时候忙完项目,有两个星期的调整优化时间,最近在整理公司的统一开发者平台的技术文档,因为项目中使用的React,所以笔者看了一下阮一峰的EcmaScript入门这本书,对Es6语法以及一些新特性进行了梳理。以下为项目中一些常见的用法,仅供参考。

一、 let命令

用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。(块级作用域)

  1. 基础用法

示例:

{
let a = 10;
var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

2.变量提升问题

var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined。建议变量都声明了再使用,避免这种问题。

let命令所声明的变量一定要在声明后使用,否则报引用错误。

console.log(a); //undefined
var a = "weixiaohuai";

console.log(b); //ReferenceError引用错误
let b = "weixiaohuai";
console.log(b); //weixiaohuai 先声明再使用

3.不允许重复声明
在同一个块级作用域中,let声明的变量不允许重复声明,否则会报错。

示例:

test = () => {
let a = 'weixiaohuai';
let a = 'hello world'; //报错 重复声明
};

报错如下图:

4.块级作用域

es6中let提供了块级作用域,在同一个作用域内,不能重复声明一个变量,但是在不同的作用域可以声明名字相同的变量。

如下:

test = () => {
let temp = 'hello';
if (true) {
let temp = 'world';
console.log(temp); //world
}
console.log(temp); //hello
}

二、const命令

  1. 基本用法

    const用于声明一个常量,一旦声明之后它的值就不能再修改,相当于java中的final常量。const只声明不赋值,就会报错,所以定义的时候就必须初始化。

示例:

const temp1; //报错:必须初始化 const variable without initializer is not allowed
const temp2 = 'hello world';
console.log(temp2); //hello world
temp2 = 'weixiaohuai'; //报错 const不能再改变值
  1. 块级作用域与不可重复声明

    const跟let一样都是块级作用域,在同一个作用域内,不能重复声明,但是在不同的作用域可以声明名字相同的const常量。

示例:

test = () => {
const a1 = 'hello weixiaohuai';
// const a1 = 'hello'; //报错,不能重复声明 Block scoped variables cannot be redeclared
if (true) {
const a1 = 'hello'; //不同块级作用域,可以重复声明
console.log(a1); //hello
}
console.log(a1); //hello weixiaohuai
};
  1. const本质(指针不变性思想类似java)

    const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址).

示例:

test = () => {
const obj = {};
obj.age = 18;
obj.name = 'weixiaohuai';
for (let item in obj) { //循环遍历obj的属性
console.log(obj[item]); //18 weixiaohuai
}

// obj = {}; // 将obj指向另一个对象,就会报错 ReadOnly (等同于改变了它的指针指向,实际上指针不可变)
};

三、变量的解构赋值

  1. 数组的解构赋值

a. 基本用法:ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。只要左右两边的模式相同,就可以解构。个人觉得有些类似正则匹配的赶脚。

示例:

let [first, [[second], third]] = [1, [[2], 3]];
console.log(first); // 1
console.log(second); // 2
console.log(third); // 3

let [ , , c] = ["a", "b", "c"];
console.log(c); // c

let [d, , f] = [1, 2, 3];
console.log(d); // 1
console.log(f); // 3

let [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); //...为扩展运算符 [2, 3, 4]

// 如果解构不成功,变量的值就等于undefined。
let [test1] = [];
let [g,i] = [1];
console.log(test1); //undefined
console.log(g); //1
console.log(i); //undefined

b. 不完全解构:就是模式相同的才解构,其他不解构。

示例:

//完全解构
let [x, [y, y2], z] = ['a', ['b', 'c'], 'd'];
console.log(x); //'a'
console.log(y); //'b'
console.log(y2); //'c'
console.log(z); //'d'
//不完全解构
let [x1, [y1], z1] = ['a', ['b', 'c'], 'd'];
console.log(x1); //'a'
console.log(y1); //'b'
console.log(z1); //'d'

c. 默认值:在解构的时候可以指定默认值,当匹配的值与undefined 严格相等的时候,就会使用默认值。严格相等的意思就是: 默认值===undefined为true。

示例:

let [flag = true] = [];
console.log(flag); //true

let [age, name = 'weixiaohuai'] = [18, undefined];
console.log(age); //18
console.log(name); //weixiaohuai

let [a = 'weixiaohuai'] = [null];
console.log(a); //null 因为null === undefined 为false,也就是不满足严格相等
  1. 对象的解构赋值

    类似于数组,对象也可以进行解构赋值。匹配的原则相同,有一个不同的就是数组是根据下标顺序匹配值,而对象是根据属性名称进行匹配值。所以属性的声明顺序无关匹配的值。

示例:

//基本用法
let {name, age} = {age: 18, name: "weixiaohuai"};
console.log(age); //18
console.log(name); //weixiaohuai

let {sex} = {age: 18, name: "weixiaohuai"};
console.log(sex); //没有匹配到有相同key的值,返回undefined

默认值:

//默认值
let {name1 = 'weixiaohuai'} = {name1: undefined};
console.log(name1); //weixiaohuai

let {name2 = 'weixiaohuai'} = {name2: null};
console.log(name2); //null 因为null === undefined 为false,也就是不满足严格相等
  1. 字符串的解构赋值

基本用法:

let [a,b,c] = "abc";
//当变量的个数与字符串的长度相等时,一一匹配
console.log(a); //a
console.log(b); //b
console.log(c); //c

//当变量的个数与字符串的长度不相等时,按声明的变量的顺序顺序匹配
let [d, e, f, g] = 'defghi';
console.log(d); //d
console.log(e); //e
console.log(f); //f
console.log(g); //g

let str = 'weishihuai';
let {length: len} = str;
console.log(len); //10 返回str的长度
  1. 常见使用场景

a. 提取 JSON 数据

//场景一:提取json对象的数据
let obj = {
age: 18,
name: "weixiaohuai",
hobby: ['music', 'run', 'basketball']
};
let {age, name, hobby} = obj;
console.log(age); //18
console.log(name); //weixiaohuai
console.log(hobby); //['music', 'run','basketball']

b. 交换变量的值

//场景二:交换变量的值
let a = 'hello';
let b = 'world';
[a, b] = [b ,a];
console.log(a); //world
console.log(b); //hello

c. 遍历Map

//场景三:遍历Map
let userInfoMap = new Map();
userInfoMap.set("name", 'weixiaohuai');
userInfoMap.set("age", 18);
userInfoMap.set("sex", "male");
for (let [key, value] of userInfoMap) {
// name==weixiaohuai
// age==18
// sex==male
console.log(key + "==" + value);
}

四、字符串的扩展

a. 字符串的遍历

es6可以使用for..of遍历字符串

示例:

let str = 'wsh';
//依次输出 w s h
for (let item of str) {
console.log(item); // w s h
}

b. includes()、startsWith()、 endsWith()方法

includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

示例:

let name = 'wei shi huai';
console.log(name.includes('wei')); //字符串中含有'wei',所以为true
console.log(name.startsWith('wei')); //字符串以'wei'开头,所以为true
console.log(name.endsWith('!')); //字符串以'huai'结尾,所以为false

同时,这三个方法可以指定从某个位置开始检索,类似indexof方法。
示例:

let name = 'wei shi huai';
console.log(name.includes('shi', 4)); //从第四个位置开始字符串包含'shi',所以为true
console.log(name.startsWith('wei',1)); //从第一个位置开始字符串以e开头,所以为false
console.log(name.endsWith('shi',7)); //针对name前七个字符是以'shi'结尾,所以为true

c. 模板字符串

模板字符串的意思,其实就是在字符串中嵌入一些变量,使用$(xxx)的方式使用模板字符串的意思,其实就是在字符串中嵌入一些变量,使用$(xxx)的方式使用

示例:

let name = 'weishihuai', age = 18;
console.log(`hello, your name is ${name}, age is ${age}`); //hello, your name is weishihuai, age is 18

模板字符串之中还能调用函数:

示例:

add = (a, b) => {
return a + b;
};
console.log(`a + b = ${this.add(1, 2)}`); //a + b = 3

五、数值的扩展

a. Number.isNaN()

Number.isNaN()用来检查一个值是否为NaN,es6对于不是NaN参数的统一返回false

示例:

console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN(15)); // false
console.log(Number.isNaN('15')); // false
console.log(Number.isNaN(true)); // false
console.log(Number.isNaN(9 / NaN)); // true
console.log(Number.isNaN('true' / 0)); // true
console.log(Number.isNaN('true' / 'true')); // true

b. Number.isInteger()

Number.isInteger()用来判断一个数值是否为整数。es6对于不是Integer参数统一返回false

示例:

console.log(Number.isInteger(1)); //因为1是整数,所以为true
console.log(Number.isInteger(1.0)); //因为在js中整数和小数采用统一的存储方式,所以需要注意一点,所以为true
console.log(Number.isInteger(1.1)); //1.1是浮点数,所以为false

//注意: isInteger中传入的参数如果不是整数,统一返回false
console.log(Number.isInteger()); //false
console.log(Number.isInteger('weishihuai')); //false
console.log(Number.isInteger(null)); //false
console.log(Number.isInteger(NaN)); //false
console.log(Number.isInteger(false)); //false

c. Math.trunc()

Math.trunc()方法主要使用场景为:有时候对于浮点数,我们只是想要去除小数后面的部分,这时候就可以使用Math.trunc()方法,避免使用切割或者正则匹配等其他方式进行处理。Math.trunc()方法主要使用场景为:有时候对于浮点数,我们只是想要去除小数后面的部分,这时候就可以使用Math.trunc()方法,避免使用切割或者正则匹配等其他方式进行处理。

示例:

//Math.trunc()方法只返回整数部分,不会进行四舍五入处理,会保留符号位
console.log(Math.trunc(1.0)); //1
console.log(Math.trunc(1.9)); //1
console.log(Math.trunc(-1)); //-1

//Math.trunc()对于一些可以截取出整数的类型会先转换为Number再进行截取
console.log(Math.trunc(true)) ; //1
console.log(Math.trunc(false)); //0
console.log(Math.trunc('123.456')); //123
console.log(Math.trunc(null)); //0

//Math.trunc()对于空值等不能截取整数部分的直接返回NaN
console.log(Math.trunc('weishihuai')); //NaN
console.log(Math.trunc()); //NaN
console.log(Math.trunc(undefined)); //NaN
console.log(Math.trunc(NaN)); //NaN

六、函数的扩展

a. 函数参数默认值

es6允许为函数的参数传入默认值,es6之前一般采用的方法:先判断一下参数是否被赋值,如果没有,再等于默认值。

示例:

functionDefaultParam = (a, b = 2) => {
return a + b;
};

test = () => {
console.log(this.functionDefaultParam(1)); //因为b指定了默认值2,所以没传参数b会取默认值2,相加后结果为3
console.log(this.functionDefaultParam(1,3)); //4
};

b. rest参数

es6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。

示例:

//rest参数,相当于传入一个数组
restParam = (...values) => {
for (let item of values) {
console.log(item);
}
};

test = () => {
//rest参数
this.restParam('a','b','c','d'); //依次输出'a' 'b' 'c' 'd'
};

c. 箭头函数

es6新增了箭头函数的写法(a , b) => {}用于取代传统的写法function(a , b) {}

示例:

add = (a,b) => a + b;
等同于:
function(a,b) {
return a + b;
}

['a','b','c'].map((item,index) => {
console.log(item,index); //'a' 0 、 'b' 1 、'c' 2
});
等同于:
['a','b','c'].map(function (item,index) {
console.log(item,index); //'a' 0 、 'b' 1 、'c' 2
});

七、数组的扩展

a. 扩展运算符…

扩展运算符其实是rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。比如…[a,b,c]其实就是a,b,c

示例:

add = (a,b) => {
return a + b;
};

test = () => {
console.log(...['wei','shi','huai']); //wei shi huai
console.log(this.add(...[1,2])); //相当于1+2=3
};

b. 常见使用场景:

(1).复制数组:

如果两个数组直接用=赋值的话其实不是值的copy,而是指针的copy,这样对新数组的改变,原数组也会变化。es6之前通常使用[].concat()来复制一个数组,es6可以使用扩展运算符进行数组复制。

示例:

test = () => {
let arr1 = ['wei', 'shi', 'huai'];
let arr2 = arr1.concat();
for (let item of arr2) {
console.log(item); //wei shi huai
}

//改变新数组并不会改变原数组的值
arr2[0] = 'weiweiwei';
for (let item of arr1) {
console.log(item); //wei shi huai
}
for (let item of arr2) {
console.log(item); //weiweiwei shi huai
}

//扩展运算符复制数组
let arr3 = [...arr1];
for (let item of arr3) {
console.log(item); //wei shi huai
}

};

(2).数组合并

示例:

//数组合并
//需要注意的是:浅拷贝。如果修改了原数组的成员,会同步反映到新数组。
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

// ES5
console.log(arr1.concat(arr2, arr3)); // [ 'a', 'b', 'c', 'd', 'e' ]
// ES6
console.log([...arr1, ...arr2, ...arr3]); // [ 'a', 'b', 'c', 'd', 'e' ]

(3).将字符串转换为数组

示例:

let str = 'weishihuai';
console.log([...str]); //["w", "e", "i", "s", "h", "i", "h", "u", "a", "i"]

c. Array.from() Array.of()方法

Array.from()是将类似数组的对象(array-like object)和可遍历(iterable)的对象转换成数组, Array.of()则是将一组值转换为数组。

示例:

console.log(Array.from('weishihuai')); //字符串组成数组: ["w", "e", "i", "s", "h", "i", "h", "u", "a", "i"]
console.log(Array.of(1,2,3,4,5)); //值组成数组:[1, 2, 3, 4, 5]

d.数组实例的 entries(),keys() 和 values()

数组实例的 entries(),keys() 和 values()主要用于对数组的遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

示例:

//数组实例的 entries(),keys() 和 values()
let arr = ['wei', 'shi', 'huai'];
//第一种方法
for (let item of arr) {
console.log(item); //'wei' 'shi' 'huai'
}

//第二种方法
for (let index of arr.keys()) {
//输出键值
console.log(index); // 0 1 2
}

for (let item of arr.values()) {
//输出值
console.log(item); //'wei' 'shi' 'huai'
}

for (let [index, item] of arr.entries()) {
//输出键值对
console.log(index, item); // 0 'wei'、1 'shi'、2 'huai'
}

e.includes()方法

includes()方法主要用于判断数组中是否包含某个值,es6之前通常采用indexof()方法进行判断。

示例:

//includes()
let arr = ['wei', 'shi', 'huai', NaN];
console.log(arr.includes('wei')); //true
console.log(arr.includes('wei', 1)); //从下标为1的位置开始查找,false
console.log(arr.includes(NaN)); //true
console.log(arr.includes('huai', -2)); //倒数第二个开始查找,true

八、对象的扩展

a. Object.is()

Object.is()方法用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。

示例:

//Object.is()
console.log(Object.is('weishihuai', 'weishihuai')); //'weishihuai'==='weishihuai'为true,所以结果为true
console.log(Object.is({}, {})); //{} === {}为false,所以结果为false

//注意NaN以及+0 -0问题
console.log(Object.is(NaN, NaN)); //true
console.log(NaN === NaN); //false

console.log(Object.is(+0, -0)); //false
console.log(+0 === -0); //true

b.Object.assign()

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target),是浅拷贝,拷贝的是引用。

注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

主要用途有:合并对象、添加属性、复制对象等等

示例:

//Object.assign()
let obj1 = {name: 'weishihuai'};
let obj2 = {age: 18};
let obj3 = {sex: 'male'};
//合并obj1 obj2 obj3
console.log(Object.assign(obj1, obj2, obj3)); //{name: "weishihuai", age: 18, sex: "male"}

//同名属性后面覆盖前面
let obj4 = {age: 20};
console.log(Object.assign(obj1, obj2, obj3, obj4)); //{name: "weishihuai", age: 20, sex: "male"}

//为obj5对象添加一个属性age
let obj5 = {name: 'weishihuai'};
console.log(Object.assign(obj5, {age: 18})); //{name: "weishihuai", age: 18}

//克隆对象
let obj6 = {name: 'weishihuai', age: 18};
let obj7 = Object.assign({}, obj6);
console.log(obj7); //{name: 'weishihuai', age: 18}

c. 对象属性的遍历

es6中对象属性的遍历主要有for..in、Object.keys(obj)、Object.getOwnPropertyNames(obj)等方法。

示例:

//对象属性的遍历
let obj = {name: 'weishihuai', age: 18, sex: 'male'};
//第一种方法
for (let prop in obj) {
console.log(prop); //name age sex
}
//第二种方法
let propArr = Object.keys(obj);
for (let prop of propArr) {
console.log(prop); //name age sex
}
//第三种方法
let propArr2 = Object.getOwnPropertyNames(obj);
for (let prop of propArr2) {
console.log(prop); //name age sex
}

d.Object.keys(),Object.values(),Object.entries()

Object.keys(),Object.values(),Object.entries()主要用于对象的遍历:

示例:

let obj = {name: 'weishihuai', age: 18};
for (let key of Object.keys(obj)) {
console.log(key); //name age
}

for (let value of Object.values(obj)) {
console.log(value); //weishihuai 18
}

for (let [key, value] of Object.entries(obj)) {
console.log([key, value]); // ["name", "weishihuai"] ["age", 18]
}

e.对象的扩展运算符

对象的扩展运算符(…)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

主要用途:合并对象、取出对象可遍历属性等

示例:

let obj1 = {name: 'weishihuai', age: 18};
let obj2 = {...obj1};
console.log(obj2); //{name: "weishihuai", age: 18}

//等同于:
console.log(Object.assign({}, obj1)); //{name: "weishihuai", age: 18}

//合并对象
let obj3 = {name: 'weishihuai', age: 18};
let obj4 = {sex: 'male'};
console.log({...obj3, ...obj4}); //{name: "weishihuai", age: 18, sex: "male"}
//等同于
console.log(Object.assign(obj3, obj4)); //{name: "weishihuai", age: 18, sex: "male"}

注意:合并对象的时候,同样同名属性后面的属性会覆盖前面的属性。

九、Set数据结构

Set类似于数组,但是成员的值都是唯一的,没有重复的值。

a. 基本用法

示例:

//Set基本用法
let set1 = new Set();
let arr1 = ['a', 'b', 'c', 'd', 'e', 'd', 'a', 'c'];
arr1.forEach(item => {
set1.add(item);
});
//不会添加重复的值
for (let item of set1) {
console.log(item); //'a' 'b' 'c' 'd' 'e'
}

//利用Set可以去除数组重复元素
let set2 = new Set(['a', 'b', 'c', 'd', 'e', 'd', 'a', 'c']);
console.log([...set2]); //["a", "b", "c", "d", "e"]

b.操作方法(用于操作数据)

示例:

let set3 = new Set();
//添加元素
set3.add('a');
set3.add('b');
set3.add('a');
set3.add('c');
console.log(set3.size); //set长度 3
console.log(set3.has('a')); //has用于判断set中是否包含某个元素 true
console.log(set3.delete('c')); //delete删除某个元素 true
console.log(set3.size); //2

c.遍历方法(用于遍历成员)

示例:

//遍历方法
//for .. of
let set = new Set(['a', 'b', 'c']);
//输出键
for (let item of set.keys()) {
console.log(item); //a b c
}
//输出值
for (let item of set.values()) {
console.log(item); //a b c
}
//输出键值对
for (let item of set.entries()) {
console.log(item); //a a b b c c
}

//forEach
set.forEach(item => {
console.log(item); //a b c
})

遍历的运用,set求交集,并集,差集

let a = new Set(['a', 'b', 'c']);
let b = new Set(['a', 'd', 'e']);

//a b的并集
let union = new Set([...a, ...b]);
console.log(union); //Set(5) {"a", "b", "c", "d", "e"}

// a b的交集
let intersect = new Set([...a].filter(x => b.has(x)));
console.log(intersect); //Set(1) {"a"}

// a b的差集
let difference = new Set([...a].filter(x => !b.has(x)));
console.log(difference); //Set(2) {"b", "c"}

十、Map数据结构

map类似java中的map结构,存储键值对key-value信息。

a. 实例的属性和操作方法

示例:

let map1 = new Map();
map1.set("name", "weishihuai");
map1.set("age", 18);
map1.set("sex", "male");
map1.set("age", 20);

console.log(map1.size); //map的长度 3
console.log(map1.has("name")); //判断map是否包含指定key的值 true
console.log(map1.get("name")); //根据key值取出对应的值 weishihuai
console.log(map1.delete("sex")); //删除指定key元素 true
console.log(map1.size); //2

b.遍历方法

示例:

//遍历方法
const map = new Map([
['name', 'weishihuai'],
['age', 18],
]);

for (let key of map.keys()) {
console.log(key); //name age
}

for (let value of map.values()) {
console.log(value); //weishihuai 18
}

for (let item of map.entries()) {
console.log(item[0], item[1]); //name weishihuai age 18
}

//使用扩展运算符进行遍历
console.log([...map.keys()]); // ["name", "age"]
console.log([...map.values()]); // ["weishihuai", 18]
console.log([...map.entries()]); // ["name", "weishihuai"] ["age", 18]
console.log([...map]); // ["name", "weishihuai"] ["age", 18]

猜你喜欢

转载自blog.csdn.net/Weixiaohuai/article/details/82628279
今日推荐