整合总结ES6中常用的新特性,供大家参考


一、let 和 const

var、let、const的区别?

1. var声明变量存在变量提升,let和const不存在变量提升

console.log(a); // undefined  ===>  a已声明还没赋值,默认得到undefined值
console.log(b); // 报错:b is not defined  ===> 找不到b这个变量
console.log(c); // 报错:c is not defined  ===> 找不到c这个变量
var a = 100;    
let b = 10;
const c = 10;
console.log(a);//a=100

2. let 和 const只能在块作用域里访问

if(1){
    var a = 100;
    let b = 10;
    const c = 1;
}

console.log(a); // 100
console.log(b)  // 报错:b is not defined  ===> 找不到b这个变量
console.log(c)  // 报错:c is not defined  ===> 找不到c这个变量

3. 同一作用域下 let 和 const 不能声明同名变量,而var可以

var a = 100;
console.log(a); // 控制台输出 100

var a = 10;
console.log(a); // 控制台输出 10

let a = 100;
let a = 10;

//  控制台报错:Identifier 'a' has already been declared  ===> 标识符a已经被声明了。
console.log(a);

4. const 定义常量,而且不能修改,但是在定义对象时,对象属性值是可以改变的

 const a=2
 a=3
// 控制台报错:Uncaught SyntaxError: Identifier 'a' has already been declared
 console.log(a)  
const person = {
    name : 'make',
    sex : '男'
}

person.name = 'test'

// 运行发现控制台没有报错,且 person.name 被成功修改
console.log(person.name)    

注:因为对象是引用类型的,person中保存的仅是对象的指针,而修改对象的属性不会改变对象的指针,所以这种情况就会修改成功。也就是说const定义的引用类型只要指针不发生改变,都是被允许的。

接下来我们试着修改一下指针,让person指向一个新对象,最后果然报错。

const person = {
  name : 'make',
  sex : '男'
}

person = {
  name : 'test',
  sex : '男'
}

// 控制台报错:Uncaught TypeError: Assignment to constant variable.
console.log(person.name)  // 未捕获的 TypeError: 赋值给常量变量

二、symbol

Symbol是ES6中引入的一种新的基本数据类型,用于表示一个独一无二的值,不能与其他数据类型进行运算。它是JavaScript中的第七种数据类型,与undefined、null、Number(数值)、String(字符串)、Boolean(布尔值)、Object(对象)并列。

你可以这样创建一个Symbol值:

const a = Symbol();
console.log(a);  //Symbol()

//因为Symbol是基本数据类型,而不是对象,不能 new 。
const a = new Symbol();//报错,Symbol is not a constructor

使用Symbol()创建一个Symbol类型的值并赋值给a变量后,你就得到了一个在内存中独一无二的值。现在除了通过变量a,任何人在任何作用域内都无法重新创建出这个值

const a = Symbol();
const b = Symbol();

内存解构图


三、模板字符串

在ES6之前,处理模板字符串:通过“\”和“+”来构建模板

对ES6来说:用${}来界定;反引号(``)直接搞定;

<script>
      url="xxxxxx"
       // es6之前
       let html="<div>"+
                  " <a>"+url+"</a>"+
               "</div>";
		//es6
       let eshtml=`<div>
                   <a>${url}</a>
               </div>`
</script>

可以说是非常之好用了!

3.1 字符串新方法(补充)

includes()

判断字符串是否包含参数字符串,返回boolean值。

let str = 'blue,red,orange,white';

str.includes('blue');//true

startsWith() / endsWith()

判断字符串是否以参数字符串开头或结尾。返回boolean值。这两个方法可以有第二个参数,一个数字,表示开始查找的位置。

startsWith()

该方法用于检索字符串是否以指定的子字符串开头,是则返回true,否则返回false

格式:string.startsWith( str, idx )
参数

  • str:必要,待检索的子字符串
  • idx:可选,设置从字符串的哪个位置开始查找,默认为0
let str = 'blue,red,orange,white';

str.startsWith('blue');// true
str.startsWith('bluee') // false
str.startsWith('blue',0);// false

let _strr = 'Hello world!';

_strr.startsWith('Hello') // true
_strr.startsWith('Helle') // false
_strr.startsWith('wo', 6) // true

endsWith()

该方法用于检索字符串是否以指定的子字符串结尾,是则返回true,否则返回false

格式:string.endsWith( str, idx )
参数

  • str:必要,待检索的子字符串
  • idx:可选,设置字符串的长度,默认值为原始字符串长度 string.length
let str = 'blue,red,orange,white';

str.endsWith('blue');//false

let _str = 'Hello world!';

_str.endsWith('!')       //  true
_str.endsWith('llo')     //  false
_str.endsWith('llo', 5)  //  true

repeat()

该方法按指定次数返回一个新的字符串。

console.log('hello'.repeat(2));   //'hellohello'

padStart()/padEnd()

这2个方法用参数字符串按给定长度从前面或后面补全字符串,返回新字符串。

如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全;其中,它们两个方法里都有两个参数,例:padStart(targetLength, padString);

targetLength:当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。

padString (可选参数):填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " 。

let arr = 'hell';

console.log(arr.padEnd(5,'o'));  //'hello'
console.log(arr.padEnd(6,'o'));  //'helloo'
console.log(arr.padEnd(6);  //'hell  ',如果没有指定将用空格代替
console.log(arr.padStart(5,'o'));  //'ohell'


let arr = '1';

console.log(arr.padStart(2,'0'));  // '01'

let arr = 'abc';

console.log(arr.padStart(10,'1234567'));  // 1234567abc

ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。

padStart()和padEnd()一共接受两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串。如果省略第二个参数,默认使用空格补全长度。

在年月日的格式化不满足两位自动在前面补0 的时候会用到。

formatDate(date){
   const nDate=new Date(date);
   const year=nDate.getFullYear();
   const month=(nDate.getMonth()+1).toString().padStart(2,"0");
   const day=nDate.getDay().toString().padStart(2,"0");
   return year+"-"+month+"-"+day;
}

四、解构表达式

解构赋值是对赋值运算符的扩展。它是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。字符串、以及ES6新增的MapSet 都可以使用解构表达式

参考【JS高级】ES6_参数增强、解构的简谈与应用 - CSDN博客

4.1 数组解构
let [a,b,c] = [1,2,3];
console.log(a,b,c);    //1,2,3
 
let [a,b,c] = [1,,3];
console.log(a,b,c);    //1,undefined,3
 
let [a,,b] = [1,2,3];
console.log(a,b);//1,3
 
let [a,...b] = [1,2,3];  //...是剩余运算符,表示赋值运算符右边除第一个值外剩余的都赋值给b
console.log(a,b);//1,[2,3]
4.2 对象解构

对象的解构赋值和数组类似,不过左边的变量名需要使用对象的属性名,并且用大括号{}而非中括号[]

let obj = { 
	name: "ren", 
	age: 12, 
	sex: "male" 
};

let { name, age, sex } = obj;
console.log(name, age, sex); //'ren' 12 'male'

let { name: myName, age: myAge, sex: mySex } = obj; //自定义变量名
console.log(myName, myAge, mySex); //'ren' 12 'male'

五、对象方面

5.1 Map和Set

Map 和 Set属于ES6新增加的对象

5.1.1 Map

Map对象用于保存键值对,任何JavaScript支持的值都可以作为一个键(key)或者一个值(value)。与对象不同的是

  •  object的键只能是字符串或ES6的symbol值,而Map可以是任何值。
  • Map对象有一个size属性,存储了键值对的个数,而object对象没有类似属性。 
let myMap = new Map([['name','ren'],['age',12]]);
console.log(myMap);  //{'name'=>'ren','age'=>12}

myMap.set('sex','male');
console.log(myMap);  //{'name'=>'ren','age'=>12,'sex'=>'male'}
console.log(myMap.size);  //3

myMap.get('name');  //'ren'
myMap.has('age');  //true
myMap.delete('age');  //true
myMap.has('age');  //false
myMap.get('age');  //undefined

注:Map对象myMap的输出结果如下图所示:

参考JS中Map数据结构?看这一篇就够了! 

5.1.2 Set

可以理解为后端的Set集合对象。Set对象和Map对象类似,但它存储不是键值对。类似数组,但它的每个元素都是唯一的

let mySet = new Set([1,2,3]);//里面要传一个数组,否则会报错
console.log(mySet);  //{1,2,3}

mySet.add(4);
console.log(mySet);  //{1,2,3,4}

mySet.delete(1);  //true
mySet.has(1);  //false
console.log(mySet);  //{2,3,4}

注:Set对象mySet的输出结果如下图所示:

利用Set对象唯一性的特点,可以轻松实现数组的去重

let arr = [1,1,2,3,4,4];

let mySet = new Set(arr);

let newArr = Array.from(mySet);
console.log(newArr);  //[1,2,3,4]

参考new Set( )的基本使用以及如何去重对象数组 

5.2 数组的新方法

ES6新增的数组方法

of(创建)from(转换)fill(填充);copyWithin(复制)、includes(是否存在) find(查找第一个符合的值)

findIndex(查找第一个符合的索引) flat(降低数组层级)flatMap(映射)、at(负索引)...扩展运算符;

ES5中数组常用方法

判断some()every() 遍历forEach() 、map();过滤filter()汇总reduce()和reduceRight()搜索indexOf() 和 lastIndexOf()


5.2.1 of() 方法 - 创建

创建一个由任意数量的参数组成的数组 

Array.of(1,2,3,4,5)  // [1, 2, 3, 4, 5]
Array.of()   //[]

of() 静态方法通过可变数量的参数创建一个新的 Array 实例,而不考虑参数的数量或类型。

参考Array.of() - JavaScript | MDN 

5.2.2 from() 方法 - 转换

Array.from()方法可以将可迭代对象转换为新的数组。

参考:ES6中新增Array.from()函数的用法

Array.from()是内置对象Array的方法,实例数组不能调用。

  • 函数可接受3个参数(后两个参数可以没有):
    • 第一个表示将被转换的可迭代对象(如果只有一个参数就是把形参转变成数组)
    • 第二个是回调函数,将对每个数组元素应用该回调函数,然后返回新的值到新数组,
    • 第三个是回调函数内this的指向。
let arr = [1, 2, 3];
let obj = {
    double(n) {
        return n * 2;
    }
}
console.log(Array.from(arr, function (n){
    return this.double(n);
}, obj)); // [2, 4, 6]

参考:ES6之Array.from()函数的用法详解 | Array.from() - JavaScript | MDN

5.2.3 fill() 方法 - 填充

Array.fill(0,1,2)方法用静态值填充数组中的元素。

0:用来填充的值;1:被填充的起始索引;2(可选):被填充的结束索引,默认为数组末尾

let arr =[1,2,3,4,5]
arr.fill(0);  // [0, 0, 0, 0, 0]
arr.fill(0,2);    // [1, 2, 0, 0, 0]
arr.fill(0,1,2);  // [1, 0, 3, 4, 5]

参考Array.prototype.fill() - JavaScript | MDN 

5.2.4 includes()方法 - 是否存在

includes()方法是查看数组中是否存在这个元素,存在就返回true,不存在就返回false。

■ 参数数值返回值true/false

let arr = [1,33,44,22,6,9]
let ary = arr.includes(22)
console.log(ary)

参考Array.prototype.includes() - JavaScript | MDN 

5.2.5 map() 方法 - 遍历、filter() 方法 - 过滤 _(ES5)

map()方法是要利用原数组经过运算后的数组,或者从对象数组中拿某个属性。

filter()方法是将符合挑选的筛选出来成为一个新数组,新数组不会影响旧数组。

■ 参数函数返回值数组

<script>
	let arr = [1, 33, 44, 2, 6, 9];

	let newarr1 = arr.filter((v) => v > 10); // newarr1---[33, 44]
	let newarr2 = arr.filter((v) => v * 2);  // newarr2---[1, 33, 44, 2, 6, 9]

	let newarr3 = arr.map((v) => v > 10);  // newarr3---[false, true, true, false, false, false]
	let newarr4 = arr.map((v) => v * 2);   // newarr4---[2, 66, 88, 4, 12, 18]
</script>

参考【JS高级】ES5标准规范之数组高阶函数的应用 


参考Array.prototype.map() - JavaScript | MDNArray.prototype.filter() - JavaScript | MDN

5.2.6 forEach()方法 - 遍历 _ (ES5)

forEach() 方法是循环遍历数组中的每一项,没有返回值

find()方法是查找数组中符合条件的第一个元素,直接将这个元素返回出来

■ 参数函数返回值undefined

let arr = [1,33,44,2,6,9]
let a1= []
arr.forEach((v, i)=>{
  if (v > 10) {
    a1.push(arr[i])
  }  
})
console.log(a1) // [33,44]

let a2= arr.find(v => v > 10)
console.log(a2) //33

参考Array.prototype.forEach() - JavaScript | MDN

5.2.7 find()方法 - 查找首个符合的值

find()方法是查找数组中符合条件的第一个元素,直接将这个元素返回出来。

finde()方法是返回数组中满足函数的第一个元素的值,否则返回未定义。

■ 参数函数返回值数值

let arr = [1,33,44,2,6,9]
let a= arr.find(v => v > 10)
console.log(a) // 33
let a =[1,2,3,4,5]
a.find(i=>{
	 i === 2;      // 2
	 i === 0;      // undefined
})      

 参考Array.prototype.fill() - JavaScript | MDN

5.2.8 findIndex() - 查找首个符合的值的索引

findIndex() 方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回 -1。

另请参阅 find() 方法,它返回满足测试函数的第一个元素(而不是它的索引)。

let a =[6,7,8,7,6]
a.findIndex(i=>{
   i === 7 ;      //1
   i === 0;      //-1
})     
5.2.9 some()、every() 方法 - 判断 _ (ES5)

some()方法是找到一个符合条件的就返回true,所有都不符合返回false

every()方法是数组所有值都符合条件才会返回true,有一个不符合返回false

■ 参数函数返回值true/false

let arr = [1,2,3,4,6,11]

let newarr = arr.some(function(v){
  return v > 10
})
console.log(newarr) //true

let newarr2 = arr.every(function(v){
  return v > 10
})
console.log(newarr2) //false

参考【JS高级】ES5标准规范之数组高阶函数的应用 


参考Array.prototype.some() - JavaScript | MDNArray.prototype.every() - JavaScript | MDN

5.2.10 copyWithin()方法 - 复制

copyWithin() 函数是将一部分数组元素复制到数组中的另一个位置

copyWithin() 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。

copyWithin(0,1,2)

0:要替换数据的索引位置,如果为负值表示倒数

1:从该索引位置开始读取,如果为负值表示从末尾开始计算

2(可选):到该索引位置结束,如果省略则默认为数组长度

let a =[1,2,3,4,5]

a.copyWithin(0,1)         //[2, 3, 4, 5, 5] 
//表示从数组的2开始复制数组[2,3,4,5]到索引0的开始位置

a.copyWithin(0,1,2)      // [2, 2, 3, 4, 5]
//表示从数组的22号位开始复制数组[2]到索引0的开始位置
    
a.copyWithin(1,-3,-2)    // [1, 3, 3, 4, 5]
//-3相当于2号位,-2相当于3号位 复制[3]到索引1的的位置

参考Array.prototype.copyWithin() - JavaScript | MDN 

5.2.11 flat()方法 - 降低数组层级

flat()方法通过将所有子数组平铺成一个新数组来降低嵌套数组的层级。

flat() 方法创建一个新的数组,并根据指定深度递归地将所有子数组元素拼接到新的数组中。


语法:flat() | flat(depth)


参数:depth,指定要提取嵌套数组的结构深度,默认值为 1。


返回值:一个新的数组,其中包含拼接后的子数组元素。


参考Array.prototype.flat() - JavaScript | MDN

flat() 默认只降低一级层级;flat(X) X代表降低的层数,默认为1

不管有多少层级,使用Infinity关键字作为参数,都能转化为一维数组。

let a = [1, 2, [3, 4, [5, 6]]]
a.flat()           // [1, 2, 3, 4, [5, 6]]
a.flat(Infinity)   // [1, 2, 3, 4, 5, 6]
5.2.12 flatMap()方法 - 映射

flatMap()方法是将一个数组映射为另一个数组,并将结果平铺成一个新数组。

flatMap() 方法对数组中的每个元素应用给定的回调函数,然后将结果展开一级,返回一个新数组。它等价于在调用 map() 方法后再调用深度为 1 的 flat() 方法(arr.map(...args).flat()),但比分别调用这两个方法稍微更高效一些。


语法:flatMap(callbackFn) | flatMap(callbackFn, thisArg)


参数:callbackFn,一个在数组的每个元素上执行的函数。它应该返回一个包含新数组元素的数组,或是要添加到新数组中的单个非数组值。该函数将被传入以下参数:① element,数组中正在处理的当前元素。 ② index,数组中正在处理的当前元素的索引。 ③ array,调用 flatMap() 的当前数组。

thisArg,可选在执行 callbackFn 时用作 this 的值。参见迭代方法。

返回值:一个新的数组,其中每个元素都是回调函数的结果,并且被展开一级。


参考Array.prototype.flatMap() - JavaScript | MDN

flatMap(0,1,2)

0:当前数组成员

1:当前数组成员索引

2:原数组

let a = [1, 2, 3, 4, 5]
a.flatMap(i => {
	return i * 2 // [2, 4, 6, 8, 10]
	return [
		[i * 2]
	] // [[2], [4], [6], [8], [10]]
})

a.flatMap((v, i, Array) => {
	console.log('%c ======>>>>>>>>', 'color:orange;', v, i, Array)
})
// ======>>>>>>>> 1 0  [1, 2, 3, 4, 5]
// ======>>>>>>>> 2 1  [1, 2, 3, 4, 5]
// ======>>>>>>>> 3 2  [1, 2, 3, 4, 5]
// ======>>>>>>>> 4 3  [1, 2, 3, 4, 5]
// ======>>>>>>>> 5 4  [1, 2, 3, 4, 5]

%c用于在控制台输出带有样式的文本(CSS 格式字符串)


参考:JS中常用占位符使用方法详解_ |%s|%d|%f|%o|%O|%c|-CSDN博客

5.2.13 "…" - 扩展运算符

展开语法 (Spread syntax), 可以在函数调用/数组构造时,将数组表达式或者 string 在语法层面展开;还可以在构造字面量对象时,将对象表达式按 key-value 的方式展开。(译者注: 字面量一般指 [1, 2, 3] 或者 {name: "mdn"} 这种简洁的构造方式)


参考展开语法 - JavaScript | MDN | ES6扩展运算符——三个点(...)用法详解-CSDN博客

将数组转为参数序列

let a =[1, 2, 3, 4, 5]
...(a)        // 1 2 3 4 5    

​ 相关应用

复制数组

如果只是一层数组或者对象则是深拷贝

let a = [1, 2, 3];
let b = [...a]; //[1,2,3]
b[0] = 3;
console.log(a); //[1, 2, 3]
console.log(b); //[3, 2, 3]

如果数组或对象中的元素是引用类型的元素,则是浅拷贝

let a = {
  name: "Macey",
  country: "Argentina",
  team: {
    football: "Barcelona",
  },
};
let b = { ...a };
b.team.football = "Paris Saint-Germain";
console.log(a.team.football); //Paris Saint-Germain
console.log(b.team.football); //Paris Saint-Germain

数组或对象中的元素是引用类型的元素,实现深拷贝

let a = {
  name: "Macey",
  country: "Argentina",
  team: {
    football: "Barcelona",
  },
};
let b = {
  ...a,
  team: { ...a.team },
};
b.team.football = "Paris Saint-Germain";
console.log(a.team.football); //Barcelona
console.log(b.team.football); //Paris Saint-Germain

合并数组

跟复制一样,如果只是一层数组或者对象则是深拷贝

let a = [1, 2, 3];
let b = [4, 5, 6];
a[0] = 9; //[9, 2, 3]
let c = [...a, ...b]; //[1, 2, 3, 4, 5, 6]

如果数组或对象中的元素是引用类型的元素,则是浅拷贝

let a = {
  name: "Macey",
  country: "Argentina",
  team: {
    football: "Barcelona",
  },
};
let b = {
  age: 35,
};
let c = { ...a, ...b };
c.team.football = "Paris Saint-Germain";
console.log(a.team.football); //Paris Saint-Germain
console.log(c.team.football); //Paris Saint-Germain

与解构赋值结合

通过 …rest来获取剩余的值。

let [first, ...rest] = [1, 2, 3, 4, 5]
console.log(first);    //1
console.log(rest);     //[2, 3, 4, 5]

:如果将扩展运算符放在第一位,则会报错

将字符串转化为数组

[...'es6']  // ['e', 's', '6']
5.2.14 at()方法 - 负索引

at()方法用于获取数组中指定索引的元素, 不仅可以用于数组也可以用于字符串

at() 方法接收一个整数值并返回该索引对应的元素,允许正数和负数。负整数从数组中的最后一个元素开始倒数。Array.prototype.at() - JavaScript | MDN

语法:at(index)

参数:index,要返回的数组元素的索引(从零开始),会被转换为整数。负数索引从数组末尾开始计数——如果 index < 0,则会访问 index + array.length 位置的元素。


返回值:返回数组中与给定索引匹配的元素。如果 index < -array.length 或 index >= array.length,则总是返回 undefined,而不会尝试访问相应的属性。


描述:在传递非负数时,at() 方法等价于括号表示法。例如,array[0] 和 array.at(0) 均返回第一个元素。但是,当你需要从数组的末端开始倒数时,则不能使用 Python 和 R 语言中支持的 array[-1],因为方括号内的所有值都会被视为字符串属性,因此你最终读取的是 array["-1"],这只是一个普通的字符串属性而不是数组索引。


通常的做法是访问 length 并将其减去从末端开始的相对索引。例如,array[array.length - 1]。at() 方法允许使用相对索引,因此上面的示例可以简化为 array.at(-1)。

at() 方法是通用的。其仅期望 this 具有 length 属性和以整数为键的属性。

Array.at(index)

index表示要获取的元素的索引,该参数可以是负数,表示从数组末尾开始计算的位置。

该方法返回指定索引位置的元素,如果索引越界,则返回undefined。

const arr = ["a", "b", "c", "d", "e"];
console.log(arr.at(2)); // 'c' 
console.log(arr.at(-1)); // 'e' 
console.log(arr.at(5)); // undefined 1 2 3 4 5 

该方法不会修改原始数组,而是返回一个新的值。 

5.3 object的新方法

在 ES6 中,添加了 Object.is()Object.assign()Object.keys()Object.values()Object.entries()等方法。

5.3.1 Object.is()

Object.is()方法用来判断两个值是否为同一个值,返回一个布尔类型的值。 

参考Object.is() - JavaScript | MDN

const obj1 = {};
const obj2 = {};
console.log(Object.is(obj1, obj2)); // false

const obj3 = {};
const value1 = obj3;
const value2 = obj3;
console.log(Object.is(value1, value2)); // true

引用类型数据,比较的是地址值,所以虽然obj1和obj都是空对象,但却是2个不同的对象

5.3.2 Object.assign()

Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象,并返回目标对象。

Object.assign() 静态方法将一个或者多个源对象中所有可枚举的自有属性复制到目标对象,并返回修改后的目标对象。Object.assign() - JavaScript | MDN

语法:Object.assign(target, ...sources)


参数:target,需要应用源对象属性的目标对象,修改后将作为返回值。sources一个或多个包含要应用的属性的源对象。


返回值:修改后的目标对象。

示例:对象合并

const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { a:5 , c: 3 };
//对象合并,把后面对像合并到第一个对象,对象里相同的属性会覆盖
Object.assign(obj1, obj2, obj3);
console.log(obj1); // { a: 5, b: 2 , c:3}
5.3.3 Object.keys()、Object.values()、Object.entries()

Object.keys() 返回对象所有属性 | Object.keys() - JavaScript | MDN

Object.values() 返回对象所有属性值 | Object.values() - JavaScript | MDN

Object.entries() 返回多个数组,每个数组是 key–value | Object.entries() - JavaScript | MDN

示例如下:

<script>
  let person = {
    name: "admin",
    age: 12,
    language: ["java", "js", "css"],
  };
  console.log(Object.keys(person)); //[ 'name', 'age', 'language' ]

  console.log(Object.values(person)); //[ 'admin', 12, [ 'java', 'js', 'css' ] ]

  console.log(Object.entries(person));    /* [
  ["name", "admin"],
  ["age", 12],
  ["language", ["java", "js", "css"]],
  ]; */
</script>
5.4 对象声明简写
<script>

  let name ='admin'
  let age = 20
          //es6之前
       // let person={
       //     name:name,
      //      age:age
     //   }

    // es6 声明对象时的属性名与引用的变量名相同就可以省略
    let person={
       name,
       age
    }
</script>
5.5 …(对象扩展符)

拷贝对象

<script>
  let person={
    name: "admin",
    age: 12,
    wife:"迪丽热巴"
  }

  let person2={...person}

  console.log(person2===person);//false
  console.log(person2);//{name: 'admin', age: 12, wife: "迪丽热巴"}
</script>

合并对象

<script>
  const obj1 = {a: 1 };
  const obj2 = {b: 2 };
  const obj3 = {a: 5, c: 3 };

  let newObj ={...obj1,...obj2,...obj3}
  console.log(newObj); // {a: 5, b: 2 , c:3}
</script>l

六、函数方面 

6.1 参数默认值
<script>

	// es6之前
	// function add(a, b) {
	//     if(!a) a=0
	//     if(!b) b=0
	// 	return a + b;
	// }
	
	//es6
	function add(a = 0, b = 0) {
		return a + b;
	}
	let x=add(); 
	let y=add(2); 
	let z=add(3, 4); 
    console.log(x,y,z); // x=0+0, y=2+0, z=3+4
</script>
6.2 箭头函数

箭头函数实现了一种更加简洁的书写方式。箭头函数内部没有arguments,也没有prototype属性,所以,不能用new关键字调用箭头函数。

let add = (a,b) => {
    return a+b;
}
let print = () => {
    console.log('hi');
}
let fn = a => a * a;
//当只有一个参数时,括号可以省略,函数体只有单行return语句时,大括号也可以省略。

箭头函数和普通函数最大的区别在于其内部this永远指向其父级对象的this。(重点)

var age = 123;
let obj = {
    age:456,
    say:() => {
         console.log(this.age);  // this指向window
    }
};
obj.say();   //123

 参考【JS高级】ES6_箭头函数 - CSDN博客


七、class(类)

class 作为对象的模板被引入ES6,你可以通过 class关键字定义类。class的本质依然是一个函数。

 创建类

<script>
	class person {
		// 关键字声明方式
		constructor(name) {
            this.name=name
        }           
		say() {
			console.log("hello");
		}
	}

	var p = new person('p');
	p.say(); // 'hello'
	console.log(p.name); // p
</script>

  类的继承

类的继承通过extends关键字实现。子类必须在constructor中调用super()

<script>
	class Person {
		constructor(name, age) {
			this.name = name;
			this.age = age;
		}
		say() {
			console.log(this.name + ":" + this.age);
		}
	}
	class Student extends Person {
		constructor(name, age, sex) {
			super(name, age);
			this.sex = sex;
		}
	}
	var student = new Student("admin", 12, "male");
	student.name;   //'admin'
	student.sex;    //'male'
	student.say(); //'ren:12'
</script>

八、promise对象

Promise属于ES6新增的一个对象, 它是一个内置构造函数,可直接调用。如何使用 Promise - 学习 Web 开发 | MDN

英文意思是:承诺

有三种状态:pending-等待态,即初始状态,resolved(fulfilled)-成功态,rejected-失败态

new Promise 的时候传入一个参数executor——执行器函数

executor函数也有两个参数,resolve 和 reject,这两个参数也是函数,调用resolve或reject时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。Promise 状态只能唯一

=〉1 这个执行器会立即执行

=〉2 这个执行器接受两个函数参数 分别是resolve和rejict

=〉3 调用resolve,会把promise状态从pending—>resolved

       ​ 调用reject,会把promise状态从pending—>rejected

基本用法

const  p = new Promise((resolve, reject) => {
	console.log(123);
    resolve('我成功了');
  // reject('我失败了');
})

then方法的使用

// promise实例的then方法(then方法是异步的),当p的状态是成功的时候,第一个回调函数会被执行,当p的状态是失败的时候, 第二个回调函数会被执行
p.then(res => {
  console.log('SUCCESS',res);
},error => {
  console.log('ERROR',error);
})
console.log(456);
//最终输出结果如下: 
// 123     
// 456    
// SUCCESS 我成功了

then的链式调用

p.then().then()....

// 第一个then到底执行哪个回调,取决于p的状态
// 后面的then到底执行哪个回调 取决于上一次then执行的回调函数的返回值
// => 假如上一次then返回的是普通纸,数字、字符串、对象。。。 那么本次then执行成功回调
// => 假如上一次then返回的是Promise对象,假如该Promise对象是成功态,本次then执行成功回调,失败态,本次then执行失败回调
// => 上一次then回调函数执行过程中出错,直接走下一次then的失败回调。
p.then((r) => {
  console.log('aaa',r);
  return 1; // 不写return默认返回undefined  return结果会作为下一个then成功回调参数。
  // reject(); 则走下一个then的失败回调
}).then((r) => {
  console.log('bbb',r)
})

// 最终输出结果如下:
// aaa 我成功了
// bbb 1

catch方法的使用

// 失败态的时候 会执行catch传入的回调函数
const  p = new Promise((resolve, reject) => {
	console.log(123);
    // resolve('我成功了');
    reject('我失败了');
})

p.catch(e => {
  console.log('Fail',e);
});

输出结果如下:

我的疑问???:race()函数最终返回的Promise实例的Promise Result值为什么是undefined,不应该是 "我失败了" 吗?待解决...... 

all方法的使用

Promise 的 all 方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。

// 异步并发时,可以用all方法,并且返回结果是一个数组,数组结果的顺序则是请求的先后顺序,不会改变。
// 并且每个请求都成功才会返回成功结果数组,否则会报错
const p1 = new Promise((resolve,reject) => {
  // 异步
  setTimeout( ()=> {
    resolve('success1');
  },5000);
});
const p2 = new Promise((resolve,reject) => {
  // 异步
  setTimeout( ()=> {
    resolve('success2');
  },1000);
})
const p3 = new Promise((resolve,reject) => {
  // 异步
  setTimeout( ()=> {
    resolve('success3');
  },1000);
})
Promise.all([p1,p2,p3]).then((res) => {
  console.log(res); // ['success1','success2','success3']
})

执行结果如下:

async 和 await (ES7语法,ES6中已有提案)

异步流程 回调 —> promise —> generator —> async+await

// async是函数修饰关键字
// await 必须在async修饰的函数内部使用
// await 后面是一个promise对象才有意义
async function fn() {
  const res = await this.getList(); // this.getList()获取列表数据的请求函数
  console.log(res);
}

generrator 生成器函数(不是函数,生成迭代器)

// 在生成器函数内部使用yield关键字
// =》暂停代码执行
// =》返回一个结果
function* fn() {
  console.log('第一部分代码'); 
  yield '第一部分代码end';
  console.log('第二部分代码');
  yield '第二部分代码end';
	console.log('第三部分代码');
  yield '第三部分代码end';
  console.log('第四部分代码');
  return '第四部分代码end';
} 
const iterator = fn(); // 迭代器
console.log(iterator);
// 迭代器有个next方法
const {value, done} = iterator.next(); // value:第一部分代码end  done:false
iterator.next(); // 打印 第二部分代码
iterator.next(); // 打印 第三部分代码
iterator.next(); // 打印 第四部分代码
iterator.next(); // 没有执行,因为已经return了

参考JS高级 - Promise使用方法详解 


九、proxy对象

参考JS高级 - Proxy使用方法详解


十、模块化

10.1 导入

ES6使用关键字 import导入模块(文件),有两种常用的方式:

import ‘模块名称’  from  ‘路径’;
import  ‘路径’;

通过 import...from 的方式引入模块,模块名称实际上相当于定义一个变量,用来接收即将导入的模块。

路径可以有很多方式,既可以是绝对路径,也可以是相对路径,甚至只是一个简单的模块名称,更甚至连文件后缀都不需要。当你使用该命令时,系统会自动从配置文件中指定的路径中去寻找并加载正确的文件。

import Vue from "vue";
//完整路劲其实是 "../node_modules/vue/dist/vue.js";

通过 import... 的方式一般用来引入样式文件或预处理文件,因为他们不需要用变量来接收。

10.2 导出

ES6 通过 export 和 export default 导出模块。

默认导出:export default

export var name = 'ren';

按需导出:export  

let name = 'ren',age = 12;
export {name,age};
//注意:变量需要用大括号包裹,然后才能向外输出

总结:使用 export 向外输出成员时,可以同时输出多个,并且必须用‘{}’大括号包裹,在其他地方使用 import 导入时,接收成员的变量名必须和这里输出的名称一致,同时,可以根据实际情况,仅接收实际需要的的成员(接收的时候也要用大括号包裹)。 

export 向外暴露成员,并且在导入的时候自定义接收名称,那么你可以使用 as 关键字重命名。 

let name = 'ren'
let age = 12;
export {name, age};
 
import {name as myName, age as myAge} from 'url';

export default与export 的不同:

①、在同一个模块中,export default 只允许向外暴露一次成员;然后,这种方式可以使用任意的名称接收;

②、export 和 export default 可以在同一模块中同时存在。 

let person = {name: 'ren'};
let age = 12;
let address = 'cd';
export default person;
export {age};
export {address};
 
import man,{age, address} from 'url'

参考: export default 和 export之间的区别

模块化优点:① 防止命名冲突;② 复用性强 


十一、运算符(操作符)

11.1 扩展运算符 ...

参考ES6扩展运算符——三个点(...)用法详解 | 展开语法 - JavaScript | MDN

11.2 可选链运算符 ?.

在  ES5 中对于安全地访问对象的深嵌套属性时,首先检查它的上一个属性是否存在,然后才能获取属性的值,否则就会报错:

var obj = {}

console.log(obj.a) // undefined

// Uncaught TypeError: Cannot read properties of undefined (reading 'b')
console.log(obj.a.b) 

上面的代码中,obj 是一个对象,在获取 obj 对象的属性 a 时,属性 a 没有被定义所以返回 undefined,第 3 行获取 obj 对象 a 下的 b,由于 obj 上没有 a 属性,再获取 a 上的 b 属性就会报错。一般这样的情况,在程序中需要做前置验证,大部分情况会借助 && 来完成。

var obj = {}

var b = obj.a && obj.a.b

console.log(b) // undefined

上面的代码中第 2 行首先会判断 obj.a 的值,如果不为空则继续执行 obj.a.b 否则返回 undefined。这样做虽然能保证程序的健壮性,但当嵌套的对象很深时,则要对每一层进行验证,这样不利于阅读,而且容易出现程序上的错误。

针对上面的场景,ES2020 最新的版本给出了它的解决方案 —— 可选链操作符。我们可以直接在浏览器的控制台中进行测试,那什么是可选链操作符呢?本节我们来学习这个 ES6 的新语法。

11.2.1 方法详情

可选链操作符使用 ?. 来表示,可以判断操作符之前属性是否有效,从而链式读取对象的属性或返回 undefined 。

作用与 . 操作符类似。不同的是 ?. 如果对象链上的引用是 null 或者 undefined 时, . 操作符会像上面的例子中一样抛出一个错误,而 ?. 操作符则会按照短路计算的方式进行处理,返回 undefined。可选链操作符也可用于函数调用,如果操作符前的函数不存在,也将会返回 undefined。下面我们来看它的使用语法:

基本语法

obj?.prop

obj?.[expr]

arr?.[index]

func?.(args)

参数解释

参数描述
prop对象上的属性
expr对象上的属性可以是一个表达式
index对数组使用时,可以接数组的位置
args对函数使用时,可以接收传入的参数

基本实例

var user = {
    name: 'Kira',
    address: {
    city: 'beijing',
    other: {}
    }
}

console.log(user?.name); // Kira
a?.b); // undefined
console.log(user?.address?.city); // beijing
console.log(user?.address?.other?.a?.b); // undefined

上面的代码可以看出,使用的方式很简单,在确保上一个值是有效时才会去获取下面的属性,避免程序报错。

对象的引用或函数可能是 undefined 或 null 时,可选链操作符提供了一种方法来简化被连接对象的值访问。

11.2.2 使用场景
  • 可选链和表达式

当使用方括号与属性名的形式来访问属性时,你也可以使用可选链操作符:

let firstName = obj?.['first' + 'Name'];
  • 可选链与函数调用

当尝试调用一个可能不存在的方法时也可以使用可选链。这将是很有帮助的,当函数调用时如果被调用的方法不存在,使用可选链可以使表达式自动返回 undefined 而不是抛出一个异常。

var person = {}

var name = person.getName?.();

注意:如果属性名不是函数也会报错,可选链只会判断属性是否有效,而不能判断属性的类型。

var person = {getName: ''}

var name = person.getName?.();

// Uncaught TypeError: person.getName is not a function
  • 处理可选的回调函数或者事件处理器

如果使用解构赋值来解构的一个对象的回调函数或 fetch 方法,你可能得到不能当做函数直接调用的不存在的值,除非你已经校验了他们的存在性。使用?.的你可以忽略这些额外的校验:

//  ES2019 的写法
function doSomething(onContent, onError) {
  try {
    // ... do something with the data
  } catch (err) {
    if (onError) {
      // 校验 onError 是否真的存在
      onError(err.message);
    }
  }
}
// 使用可选链进行函数调用
function doSomething(onContent, onError) {
  try {
    // ... do something with the data
  } catch (err) {
    onError?.(err.message); // 如果 onError 是 undefined 也不会有异常
  }
}
  • 可选链不能用于赋值

可选链是取值操作时所用的安全方法,不能使用在赋值操作上。

let obj = {};

obj?.name = '5axxw'; // Uncaught SyntaxError: Invalid left-hand side in assignment

上面的代码第 2 行使用可选链进行赋值操作,控制台会报语法错误,赋值的左侧是无效的。

  • 可选链访问数组元素

可选链也是可以使用在数组取值的前置验证的。

var arr = []

let item = arr?.[5]; // undefined
◆◆ 示例 ◆◆

基本用法

在一个不含 bar 成员的 Map 中查找 bar 成员的 name 属性,因此结果是 undefined

let myMap = new Map();
myMap.set("foo", {name: "baz", desc: "inga"});

let nameBar = myMap.get("bar")?.name;

短路计算

当在表达式中使用可选链时,如果左操作数是 null 或 undefined,表达式将不会被计算

let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // x 将不会被递增,依旧输出 0

连用可选链操作符

可以连续使用可选链读取多层嵌套结构:

let customer = {
  name: "Carl",
  details: {
    age: 82,
    location: "Paradise Falls" // details 的 address 属性未有定义
  }
};
let customerCity = customer.details?.address?.city;

// … 可选链也可以和函数调用一起使用
let duration = vacations.trip?.getTime?.();

使用空值合并操作符

空值合并操作符可以在使用可选链时设置一个默认值:

let customer = {
  name: "Carl",
  details: { age: 82 }
};
let customerCity = customer?.city ?? "123";
console.log(customerCity); // 123

参考:空值合并运算符(??) - JavaScript | MDN 


语法:leftExpr ?? rightExpr

空值合并运算符??)是一个逻辑运算符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。

逻辑或运算符(||)不同,逻辑或运算符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 || 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如,'' 或 0)时。见下面的例子。

const foo = null ?? 'default string';
console.log(foo);
// Expected output: "default string"

const baz = 0 ?? 42;
console.log(baz);
// Expected output: 0
◆◆ 小结 ◆◆

ES6 中新增的可选链语法,它提供了一种方法来简化被连接对象的值访问,保证访问数据的安全性。它可以用于对象、数组、函数中。这个语法很有用,在项目中使用可以达到事半功倍的效果。

参考可选链运算符(?.) - JavaScript | MDN

11.3 函数绑定运算符::

“函数绑定”(function bind)运算符,用来取代callapplybind调用

函数绑定运算符是并排的两个双引号(::),双引号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。

let log = ::console.log;
// 等同于
var log = console.log.bind(console);

foo::bar;
// 等同于
bar.call(foo);

foo::bar(...arguments);
i// 等同于
bar.apply(foo, arguments);

※ — ES6思维导图总结 — 


※ — 参考资料 — ※ 

你需要知道的ES6—ES13开发技巧! - 知乎 | JS数组中的一些常用的方法(es5+es6) - CSDN博客

  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

儒雅的烤地瓜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值