ES6新特性

在这里插入图片描述

ES6新特性

ES6

一、ES6相关介绍

1.1、什么是ES6

1995年的美国,有一家名为netscape(网景)的公司打造了一款主要用于check验证的脚本语言,而恰在此时,Sun公司的java语言火的一塌糊涂,netscape公司为蹭其热度,便将该脚本语言命名为 JavaScript。不料 JavaScript居然被越来越多的人使用,后效仿大秦的货币统一政策将其提交给国际标准组织ECMA

该组织发布的标准被称做ECMAScript。 2015年6月发布的版本称为ECMAScript2015,简称ES6。从ES6开始,该组织每年会发布一个版本,版本号比年份最后一位大1,至今最新版本为ES12

ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准

ES6是一大盒语法糖,解决了以前ES5很多难受的地方。

BabelBabel是一个广泛使用的ES6转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。这意味着,你可以用ES6的方式编写程序,又不用担心现有环境是否支持。

二、关键字扩展

2.1、let和块级作用域

2.1.1、ES5没有块级作用域

ES5中,JS的作用域分为全局作用域和局部作用域。通常是用函数区分的,函数内部属于局部作用域。

ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景

  • 内层变量可能会覆盖外层变量。

    var userName = "zhangsan";
    if(true){
        var userName ="lisi";
    }
    console.log(userName);// lisi
    
  • 用来计数的循环变量泄露为全局变量。

    // for(var i=0;i<10;i++){
    //
    // }
    // console.log(i);// 10
    
2.1.2、块级作用域
  • ES6中新增了块级作用域的概念,使用{}扩起来的区域叫做块级作用域

    {
        // 块级作用域
    }
    
  • let关键字声明变量,实际上为 JavaScript 新增了块级作用域。

    {
        let userName = "zhangsan";
        userName = "lisi";
        console.log(userName);// lisi
    }
    console.log(userName);
    
  • 块作用域由 { } 包裹,if语句和for语句里面的{ }也属于块作用域。

    if(true){
        let age = 100;
    }
    for(let i=0;i<10;i++){
        console.log(i);
    }
    // console.log(age);// ferenceError: age is not defined
    console.log(i);// ferenceError: i is not defined
    
  • 在块内使用let声明的变量,只会在当前的块内有效。

    {
        let a =1;
        a = 2;
        console.log(a);
    }
    console.log(a);// 异常
    
2.1.3、let关键字

ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,也就是增加了块级作用域。

  • 使用块级作用域(let定义的变量属于块级作用域) 防止全局变量污染
let age = 1;
{
   let age = 2;
}
console.log(age);// 1
  • 块级作用域可以任意嵌套
{
   let a = 1;
   {
       let a = 2;
       {
           let a = 3;
           console.log(a);// 3
       }
       console.log(a);// 2
   }
   console.log(a);// 1
}
  • for循环的计数器,就很合适使用let命令
var btns = document.querySelectorAll("button");
for(let i=0;i<btns.length;i++){
    btns[i].onclick = function(){
        console.log(i);
    }
}
  • 变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量

你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算

var btns = document.querySelectorAll("button");
{
 let i = 0;
 btns[i].onclick = function(){
     console.log(i);
 }
}
{
 let i = 1;
 btns[i].onclick = function(){
     console.log(i);
 }
}
{
 let i = 2;
 btns[i].onclick = function(){
     console.log(i);
 }
}
{
 let i = 3;
 btns[i].onclick = function(){
     console.log(i);
 }
}
{
 let i = 4;
 btns[i].onclick = function(){
     console.log(i);
 }
}
  • for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域

    • 练习1
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
   console.log(i);
};
}
a[6]();
  • 练习2
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6]();
2.1.4、let关键字特点
  • let命令不存在变量提升
console.log(a);// ferenceError: Cannot access 'a' before initialization
let a = 1;
console.log(a);// 1
/***************************************************/
function fn(){
   console.log(userName);
}
// fn();// 异常
let userName = "lisi";
fn();// 正常

和var不同的还有,let命令不存在变量提升,所以声明前调用变量,都会报错,这就涉及到一个概念——暂时性死区。

暂时性死区即:区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

  • 不允许重复声明

let 只能声明一次而var 可以声明多次。

console.log(1);
let a = 1;
let a = 2;
console.log(a);// 异常
  • 块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式不再必要了
// 匿名函数立即调用:
// (function (){
// 	var a = 1;
// 	console.log(a);
// })();
// console.log(a);// ferenceError: a is not defined
       
// 块级作用域:
{
   let a = 1;
   console.log(a);
}
  • let 是在代码块内有效,var 是在全局范围内有效
{
   var a = 1;
   let b = 2;
}
console.log(a);// 1
console.log(b);// 异常
  • 不影响作用域链

let与var都拥有作用域链。

作用域链: 如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。

{
 let a = 300;
 {
     let a = 200;
     {
         let a = 100;
         console.log(a);// 100
     }
     console.log(a);// 200
 }
 console.log(a);// 300

}
  • 不再是顶层全局对象的属性

使用var定义的全局变量相当于直接挂载在window对象上, 而let不会。

let b = 2;
console.log(window.b);// undefined
console.log(this.b);// undefined

2.2、const 关键字

注意:

​ 变量:数据可以变化。在执行过程当中,有一些数据会使用多次,根据条件会变化,一般定义为变量。

​ 常量:不会变化的数据,有些时候有的数据是不允许修改的,所以需要定义常量。

  • 声明一定要赋初始值:一旦声明变量,就必须立即初始化,不能留到以后赋值

const 声明一个只读变量,声明之后不允许改变。意味着,一旦声明必须初始化,否则会报错。

const userName;// 语法错误,必须要设置初始值
  • 值不允许修改
const userName = "zhangsan";
userName = "lisi";// 异常

const 其实保证的不是变量的值不变,而是保证变量指向的内存地址不允许改动。所以 使用 const 定义的对象或者数组,其实是可变的。

const obj = {
 num:100
}
obj.num = 200;
console.log(obj.num);// 200

const arr = [1,2,3];
arr[0] = 20;
console.log(arr);// [20,2,3]
  • const只在声明所在的块级作用域内有效。(与let相同)
{
    const a = 1;
    console.log(a);
}
console.log(a)// 异常:ferenceError: a is not defined
  • const命令声明的常量也是不会提升(与let相同)
console.log(a);// 异常:ferenceError: Cannot access 'a' before initialization
const a = 100;
  • const不可重复声明(与let相同)
// 语法异常:ntaxError: Identifier 'age' has already been declared
	const age = 100;
+
  • 不再是顶层全局对象的属性(与let相同)

let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。

  • const使用的两点建议:

    1、被多次使用且不允许更改的数据建议通过const定义;

    2、项目全局常量建议大写,单词之间用-分隔;

    3、如果不清楚要使用let还是const,那么就用const。如果后面发生值的改变,那么再将const改成let.

    4、以后不允许使用val

2.3 、块级作用域的函数声明

  • 函数声明一般常用的是两种,一种是function声明,一种是函数表达式。

  • 建议函数在顶层作用域和函数作用域之中声明,尽量避免在块级作用域声明。

  • 如果确实需要,也应该写成函数表达式,而不是函数声明语句。

三、变量的解构赋值

let a = 1;
cosnt b = 2;
const obj = {
    
}

3.1、什么是变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。

解构赋值本质就是赋值:把结构解散重构然后赋值。

解构赋值是对赋值运算符=的一种扩展。

在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。

3.2、引入

ES5中,开发者们为了从对象和数组中获取特定数据并赋值给变量,编写了许多看起来同质化的代码 ;

// 同质化代码
// function fn(obj){
// 	console.log(obj.a);
// 	console.log(obj.b);
// 	console.log(obj.c);
// }
// fn({a:1,b:2,c:3});

// 数组
const arr = [1,2,3,4];
const a = arr[0];
const b = arr[1];
const c = arr[2];
const a = arr[3];

3.3、解构赋值语法

let a = 1;

解构的目标 = 解构源;(目标指的是定义的常量或变量,解析源一般指的是数组或对象)

解构目标:定义的常量或变量

解构源:待解构的数组或对象

3.4、对象解构赋值

  • 对象解构赋值基本语法

对象的语法形式是在一个赋值操作符= 右边放置一个对象字面量

  • 顺序不用一一对应
// 未使用解构赋值:
// const obj =  {a:1,b:2,c:3};
// const a = obj.a;
// const b = obj.b;
// const c = obj.c;
     
// 语法糖:
// 将对象下的a,b,c属性的值赋值给常量a,b,c
// const {a, b, c} = {a: 1, b: 2, c: 3};
// console.log(a,b,c);// 1 2 3
  • = 右侧可以是一个常或变量
// const {c,a,b} = {a:1,b:2,c:3};
// console.log(a,b,c);// 1 2 3
     
const obj = {userName:"zhangsan",age:12};
const {userName,age} = obj;
console.log(userName,age);// zhangsan 12
  • 嵌套对象解构

解构嵌套对象仍然与对象字面量的语法相似,可以将对象拆解以获取想要的信息

const obj = {
 type:1,
 userInfo:{
     userName:"zhangsan",
     age:12
 }
};
// const {type,userInfo} = obj;
// console.log(type,userInfo);
// console.log(userInfo === obj.userInfo);// true

// obj对象下的属性type值赋值给常量type
// const {type} = obj;

// obj对象下的属性type,userInfo赋值给常量type,userInfo
// const {type,userInfo} = obj;

// 目标:obj对象下的属性type,赋值给常量type,obj对象下的userInfo内的属性userName,age赋值给常量userName,age
// 将obj下的属性userInfo赋值给常量info
// const {type,userInfo:info} = obj;
// console.log(info);

// 将obj下的属性userInfo再次解析赋值,赋值给常量userName,age
const {type,userInfo:{userName,age}} = obj;
console.log(type,userName,age);
  • 可忽略解构源的属性
// 忽略了解构源中的a,c属性
const {b} = {a:1,b:2,c:3};
console.log(b);
  • 剩余运算符
// const {a,b,...suibian} = {a:1,b:2,c:3,d:4};
// console.log(a,b,suibian);// 1 2 {c:3,d:4}
     
// const {userName,...obj} = {userName:"lisi",age:100};
// console.log(userName,obj);// lisi {age:100}
     
// 以下写法即实现了一个对象的复制:
// const {...obj} = {userName:"lisi",age:100};
// console.log(obj);// lisi {userName:"lisi",age:100}
     
// 如果解析源是一个简单对象,那么是深复制
// const info = {userName:"lisi",age:100};
// const {...obj} = info;
// console.log(obj === info);// false
// obj.userName = "zhangsan";
// console.log(info.userName);// lisi
     
// 如果解析源是一个复杂对象,那么是浅复制(因为只会深复制一层)
// const info = {
// 	userName:"zhangsan",
// 	age:12,
// 	my:{
// 		a:1,
// 		b:2
// 	}
// }
// const {...obj} = info;
// // 相当于:
// // const obj = {
// // 	userName:info.userName,
// // 	age:info.age,
// // 	my:info.my
// // }
// console.log(obj === info);// false
// console.log(obj.my === info.my);// true
// obj.my.a = 100;
// console.log(info.my.a);// 100


// 剩余运算符只允许写在{}的最后边:以下会有异常:ntaxError: Rest element must be last element (a
const {a,...my,b} = {a:1,b:2,c:3};
console.log(a,b,my);
  • 不完全解构:变量名称在对象中不存在

使用解构赋值表达式时,如果指定的变量名称在对象中不存在,那么这个变量会被赋值为undefined

const {a,b,c,d,suibian} = {a:1,b:2,c:3,d:4};
console.log(a,b,c,d,suibian);// 1 2 3 4 undefined
  • 解构默认值(常用)

当指定的属性不存在时,可以定义一个默认值:在属性名称后添加一个等号(=)和相应的默认值即可

// const {a,b,c} = {a:1,b:2};
// console.log(a,b,c);// 1 2 undefined

// const {a,b,c=300} = {a:1,b:2};
// console.log(a,b,c);// 1 2 300

const {a,b,c=300} = {a:1,b:2,c:3};
console.log(a,b,c);// 1 2 3
  • 为非同名局部变量赋值 ,可避免命名冲突

如果希望使用不同命名的局部变量来存储对象属性的值,ES6中的一个扩展语法可以满足需求,这个语法与完整的对象字面量属性初始化程序的很像。

// 定义的常量的名字与=右侧的属性名相同。
// const {a,b,c} = {a:1,b:2,c:3};

const a = 1;
let b = 2;
const c = 3;
const obj = {
  a:10,
  b:20,
  c:30
}
const {a:aa,b:bb,c:suibian} = obj;
console.log(a,b,c,aa,bb,suibian);// 1 2 3 10 20 30
  • 函数传参数

解构赋值表达式的值与表达式右侧(也就是=右侧)的值相等,如此一来,在任何可以使用值的地方都可以使用解构赋值表达式

// function fn({a,b,c}){
// 	console.log(a,b,c);// 1 2 3
// }
// fn({a:1,b:2,c:3})

// function fn({a,...suibian}){
// 	console.log(a,suibian);// 1 {b:2,c:3}
// }
// fn({a:1,b:2,c:3})

// function fn({a, b, c:cc, d = 100}) {
// 	console.log(a, b, cc, d);// 1 2 3 100
// }
//
// fn({a: 1, b: 2, c: 3})
  • 补充
// undefined无法解构赋值
// let obj;
// const {a, b, c} = obj;

// 以下无法解构赋值
// function fn({a,b,c}){
// 	console.log(a,b,c);
// }
// fn();

// 解决:
// 如果未传递参数,默认将{}进行解构赋值。
function fn({a=10,b=20,c=30}={}){
   console.log(a,b,c);
}
fn();

3.5、数组解构赋值

  • 基本使用

与对象解构的语法相比,数组解构就简单多了,它使用的是数组字面量,且解构操作全部在数组内完成,而不是像对象字面量语法一样使用对象的命名属性 。

// const arr = [1,2,3,4];
// const a = arr[0];
// const b = arr[1];
// const c = arr[2];
// const d = arr[3];

const [a,b,c,d] = [1,2,3,4];
console.log(a,b,c,d);// 1 2 3 4

// 必须一一对应
const [c,a,b,d] = [1,2,3,4];
console.log(a,b,c,d);// 2 3 1 4
  • 忽略元素

在解构模式中,可以直接省略元素,只为感兴趣的元素提供变量名 。

const [,,,a,b,c] = [1,2,3,4,5,6];
console.log(a,b,c);// 4 5 6
  • 赋值上下文 :对之前定义的变量进行修改(重置)操作。

数组解构也可用于赋值上下文

// 数组:
// let a = 1;
// let b = 2;
// [a,b] = [10,20,30,40];
// console.log(a,b);// 10 20

// 对象:
let a = 1;
let b = 2;
({a,b}= {a:100,b:200});
console.log(a,b);// 100 200 
  • 变量交换

数组解构语法还有一个独特的用例:交换两个变量的值。在排序算法中,值交换是一个非常常见的操作,如果要在ES5中交换两个变量的值,则须引入第三个临时变量

// 交换变量,不允许使用第三方变量
// let a = 1;
// let b = 2;
// a = a + b;// 3
// b = a - b;// 1
// a = a - b;// 2
// console.log(a,b)

let a = 1;
let b = 2;
[a,b] = [b,a];
console.log(a,b);
  • 默认值

也可以在数组解构赋值表达式中为数组中的任意位置添加默认值,当指定位置的属性不存在或其值为undefined时使用默认值

// const [a,b,c,d,e] = [1,2,3,4];
// console.log(a,b,c,d,e);// 1 2 3 4 undefined

// const [a,b,c,d,e=100] = [1,2,3,4];
// console.log(a,b,c,d,e);// 1 2 3 4 100

const [a,b,c,d,e=100] = [1,2,3,4,5];
console.log(a,b,c,d,e);// 1 2 3 4 5
  • 嵌套数组解构

嵌套数组解构与嵌套对象解构的语法类似,在原有的数组模式中插入另一个数组模式,即可将解构过程深入到下一个层级

// const [a,b,c,d,e] = [1,2,[3,4],5,6]
// console.log(a,b,c,d,e);// 1 2 [3,4] 5 6

const [a,b,[c,cc,ccc=100],d,e] = [1,2,[3,4],5,6]
console.log(a,b,c,d,e,cc,ccc);// 1 2 3 5 6 4 100
  • 不定元素

函数具有不定参数,而在数组解构语法中有一个相似的概念——不定元素。在数组中,可以通过…语法将数组中的其余元素赋值给一个特定的变量

// const [a,b,...c] = [1,2,3,4];
// console.log(a,b,c);// 1 2 [3,4]

// 注意:...只允许写在最后,以下有异常
// const [a,...c,f] = [1,2,3,4];

// const [...arr] = [1,2,3,4];
// console.log(arr);// [1,2,3,4]

// const arr = [1,2,3,4];
// const [...arr2] = arr;
// 上方代码相当于:
// const arr2 = [];
// arr2.push(arr[0]);
// arr2.push(arr[1]);
// arr2.push(arr[2]);
// arr2.push(arr[3]);
// console.log(arr2 === arr);// false

// 针对于简单数组而言是深复制
// const arr = [1,2,3];
// const [...arr2] = arr;
// console.log(arr === arr2);// false
// arr2[0] = 100;
// console.log(arr);

// 什对于复杂数组而言是浅复制
const arr = [1,2,[3,4]];
const [...arr2] = arr;
console.log(arr === arr2);// false
console.log(arr[2] === arr2[2]);// true
arr2[2][0] = 300;
console.log(arr);// [1,2,[300,4]]
  • 数组复制

ES5中,开发者们经常使用concat()方法来克隆数组

// const arr = [1,2,3];
// const arr2 = [4,5,6];
// const arr3 = [7,8,9]
// console.log(arr.concat(arr2,arr3));// [1,2,3,4,5,6,7,8,9]
// console.log(arr);

const arr = [1,2,3];
const arr2 = arr.concat();
console.log(arr2===arr);

3.6、混合解构(复杂解构)

可以混合使用对象解构和数组解构来创建更多复杂的表达式,如此一来,可以从任何混杂着对象和数组的数据解构中提取想要的信息

面试题:

//复杂解构
let wangfei = {
 name: '王菲',
 age: 18,
 songs: ['红豆', '流年', '暧昧', '传奇'],
 history: [
     {name: '窦唯'},
     {name: '李亚鹏'},
     {name: '谢霆锋'}
 ]
};
const {name,age,songs:[one,two,three,four],history:[{name:name1},{name:name2},{name:name3}]} = wangfei;
console.log(name,age,one,two,three,four,name1,name2,name3);// 王菲 18 红豆 流年 暧昧 传奇  窦唯 李亚鹏 谢霆锋


// const [aa,bb,cc,{userName,age:myAge}] = [1,2,3,{userName:"wangwu",age:12}];
// console.log(aa,bb,cc,userName,myAge);

3.7、 解构传递参数

  • 解构赋值可以应用在函数参数的传递过程中。
// function fn(obj){
// 	// 同质化:
// 	console.log(obj.a);
// 	console.log(obj.b);
// 	console.log(obj.c);
// 	console.log(obj.a)
// }
// fn({a:1,b:2,c:3});
     
// function fn({c,b,a,f=100}){
// 	console.log(c,b,a,f);// 3 2 1 100
// }
// fn({a:1,b:2,c:3})
     
// function fn([a,b,c,f=10]){
// 	console.log(c,b,a,f);// 300 200 100 10
// }
// fn([100,200,300])
     
// const {0:a,1:b,2:c} = [1,2,3];
// console.log(a,b,c);
  • 如果调用函数时不提供被解构的参数会导致程序抛出错误
// typeError: Cannot destructure property 'a' of 'undefined' as it is undefined.
// function fn({a,b,c}){
// 	console.log(a,b,c);// 1 2 3
// }
// fn();
     
// 解决:
// function fn({a,b,c}={}){
// 	console.log(a,b,c);// undefined undefined undefined
// }
// fn();
     
function fn([a,b,c]=[]){
   console.log(a,b,c);// undefined undefined undefined
}
fn();

3.8、解构返回结果

  • 函数的多个返回值获取
{
   // 1
   function fn(){
       return [1,2]
   }
   // const arr = fn();
   // console.log(arr,arr[0],arr[0],arr[1],arr[1]);// [1,2]
     
   const [a,b] = fn();
   console.log(a,a,a,a,a,a,b,b,b,b,b,b);
}
{
   // 2
   function fn(){
       return {
           n:100,
           m:90
       }
   }
   const {n,m} = fn();
   console.log(n,m);// 100 90
}

3.9、字符串解构

  • 字符串也可以解构赋值。这是因为,字符串被转换成了一个类似数组的对象
// const str = "我爱你中国,我亲爱的母亲,我为你流泪也为你自豪!";
// const [a,b,c,d,e,f,g,...m] = str;
// console.log(a,b,c,d,e,f,g,m);
     
// const [a,b,c,d,e,f,g,...m] = new String(str);
// console.log(a,b,c,d,e,f,g,m);
     
// const {0:aa,1:bb} = new String(str);
// console.log(aa,bb);
     
// 可以解构原型链中的属性
// function Box(){
// 	this.num = 100;
// }
// Box.prototype.a = 200;
// Box.prototype.run = function(){
//
// };
// const {num,a,run} = new Box();
// console.log(num,a,run);// 100 200 f
     
const str = "我爱你中国,我亲爱的母亲,我为你流泪也为你自豪!";
const {length,slice} = str;
console.log(length,slice);
     
// console.log(str.slice(2));
// console.log(slice.call("abc",2));

3.10、数值和布尔值解构

  • 解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
// 数字
// let num = 100;
// const {toString,toFixed} = num;// new Number(num)
// console.log(toString,toFixed);
// console.log(100.123.toFixed(2))
// console.log(toFixed.call(100.125,2))
     
// 布尔
const {toString} = true;
console.log(true.toString());
console.log(toString.call(true))
console.log(toString.call(false))
console.log(toString.call(1))

四、字符串的扩展

4.1、模板字符串

  • 传统的 JavaScript 语言,输出模板通常要拼接字符串

    • 模板字符串(template string)是增强版的字符串,用反引号(`)标识。可以嵌套变量,可以换行,可以包含单引号和双引号。
{
    let a = "aaaaaa";
    let b = 'bbbbbb';
    let c = `cccccc`;
    console.log(a,b,c);// aaaaaa  bbbbbb  cccccc
            
    let str = "我想告诉你\"我现在过的很好\"";
    console.log(str);
    let str2 = '我想问问你\'你现在过的还好吗?\'';
    console.log(str2);
    // 可以包含单引号和双引号。
    let str3 = `'我现在过的很好!'"也祝你过的很好!"`;
    console.log(str3);
    // 可以换行
    let str4 = `
 床前明月光,
 疑是地上霜
 `;
    console.log(str4);
}
  • 它可以当作普通字符串使用,也可以用来定义多行字符串。模板字符串中嵌入变量,需要将变量名写在${}之中。

    • 大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。
let firstName = "张";
let lastName = "培跃";
let age = 18;
let str = "师法魔级超";
console.log("大家好!我的名字叫"+firstName+lastName+",我今年"+age);
console.log(`大家好!我的名字叫${firstName}${lastName},我今年${age}`);
console.log(`年龄${age}${age<=18?'少年':'未知'}`);
console.log(`${str}反转过来以后是:${str.split('').reverse().join('')}`)
- 模板字符串之中还能调用函数。
function fn(){
    return 1000;
}
// 插值表达式${}
console.log(`函数可以在插值表达式中调用${fn()}`)
console.log(`1-${11}`)
console.log(`1-${"asdfadsf"}`)
console.log(`1-${true}`)
console.log(`1-${false}`)
console.log(`1-${undefined}`)
console.log(`1-${null}`)
console.log(`1-${{a:1,b:2,c:3}}`);// 会将对象转为字符串
console.log(`1-${[1,2,3]}`);// 将[]省略,会将数组转为字符串
console.log([1,2,3].toString());
  • 模板字符串应用
const root = document.querySelector("#root");
            
// 1
// data.forEach(function (info) {
// 	root.innerHTML += "<div><h3>"+info.nm+"</h3><img height='200' src='"+info.img+"'/></div><hr/>"
// })
            
// 2
// let str = "";
// data.forEach(function (info) {
// 	str += "<div><h3>"+info.nm+"</h3><img height='200' src='"+info.img+"'/></div><hr/>"
// })
// root.innerHTML = str;
            
// 3
root.innerHTML = data.map(function(info){
    return (`
			<div>
				<h3>${info.nm}|${info.mk}</h3>
				<img height="200" src="${info.img}" alt="">
				<hr/>
			</div>
		`);
}).join("");

4.2、字符串的新增方法

  • 去空格

    • trim():删除字符串两端的空白符(常用)

    • trimStart() 去除首部的空格

    • trimEnd() 去除尾部的空格

const inp = document.querySelector("input");
inp.onkeyup = function(e){
    if(e.keyCode === 13){
        console.log("内容:","青龙"+e.target.value+"白虎")
        // - `trim()`:删除字符串两端的空白符(常用)
        console.log("trim:","青龙"+e.target.value.trim()+"白虎")
        // - `trimStart() `去除首部的空格
        console.log("trimStart:","青龙"+e.target.value.trimStart()+"白虎")
        // - `trimEnd()` 去除尾部的空格
        console.log("trimEnd:","青龙"+e.target.value.trimEnd()+"白虎")
    }
}
  • 判断

    • startsWith();判断开头有没有包含某个字符串
let str = "abc一会下课了,要吃什么呢?"
console.log(str.startsWith("abc"));// true
console.log(str.startsWith("ab"));// true
console.log(str.startsWith("a"));// true
console.log(str.startsWith("abc一"));// true
console.log(str.startsWith("一"));// false
  • endsWith();判断结尾有没有包含某个字符串
console.log(str.endsWith("abc"));// false
console.log(str.endsWith("?"));// true
console.log(str.endsWith("要吃什么呢?"));// true
  • includes判断字符串是否包含某个字符串(常用)
console.log(str.includes("下课"));// true
console.log(str.includes("abc"));// true
console.log(str.includes("cd"));// false
  • repeat重复当前的字符串,可以规定次数
let str = "发财";
console.log(str.repeat(2));// 发财发财
  • 补充字符

    • padStart()当字符串不够某个长度的时候,在前边补充任意字符
    let num = 4;
    console.log(num.toString().padStart());//  4
    console.log(num.toString().padStart(2));//  4
    console.log(num.toString().padStart(2,0));//  04
    console.log(num.toString().padStart(5,0));//  00004
    console.log(num.toString().padStart(5,"abc"));//  abca4
    
    • padEnd(),//当字符串不够某个长度的时候,在后边补充任意字符
     
let str = "A";
console.log(str.padEnd(2)+"!");// A !
console.log(str.padEnd(2,0)+"!");// A0!
console.log(str.padEnd(5,0)+"!");// A0000!
console.log(str.padEnd(5,"abc")+"!");// Aabca!
```

          * 实现封装一个函数用于获取当前时间:yyyy-mm-dd HH:mm:ss

         ```js
 // 默认返回当前时间,可以根据时间戳返回时间
 // time时间戳
 function getNowTime(time=Date.now()){
     const times = new Date(time);
     return times.getFullYear()+"-"+
         (times.getMonth()+1).toString().padStart(2,0)+"-"+
         times.getDate().toString().padStart(2,0)+" "+
         times.getHours().toString().padStart(2,0)+":"+
         times.getMinutes().toString().padStart(2,0)+":"+
         times.getSeconds().toString().padStart(2,0);
 }

         console.log(getNowTime(99999));// 2023-04-21 16:18:20

五、spread运算符与rest参数

ES6中, 三个点(…) 有2个含义。分别表示扩展运算符(spread运算符) 和 剩余运算符(rest参数)

5.1、spread运算符

  • 复制、合并数组
// 深复制
// const arr = [1, 2, 3, 4];
// const arr2 = [...arr];
// console.log(arr === arr2);// false
     
// 浅复制
// const arr = [{a:1}];
// const arr2 = [...arr];
// console.log(arr === arr2);// false
// console.log(arr[0] === arr2[0]);// true
// arr[0].a = 100;
// console.log(arr2[0].a);
     
// 合并
const arr = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = arr.concat(arr2);
console.log(arr3);
const arr4 = [...arr, ...arr2];// [1,2,3,4,5,6]
console.log(arr4);
const arr5 = [
   0,
   ...arr,
   100,
   200,
   ...arr2,
   99
];
console.log(arr5);
  • 复制、合并对象
// 复制
// const obj = {
// 	a:1,
// 	b:2,
// 	c:3
// }
// const obj2 = {...obj};
// console.log(obj2 === obj);// false
     
// 合并
// const obj = {
// 	a:1
// }
// const obj2 = {
// 	b:2
// }
// const obj3 = Object.assign({},obj,obj2);
// console.log(obj3);
//
// const obj4 = {
// 	...obj,
// 	...obj2
// }
// console.log(obj4);
//
// const obj5 = {
// 	userName:"laxi",
// 	...obj,// a:1
// 	age:12,
// 	...obj2// b:2
// }
// console.log(obj5);
  • 字符串转换为数组
let str = "abcdefg";
console.log(str.split(""));
console.log([...str]);
  • 伪数组转为真数组
// 1
// function fn(){
// 	const changeArguments = [...arguments];
// 	changeArguments.push(100);
// 	console.log(changeArguments)
// }
// fn(1,2,3,4);

// 2
[...document.querySelectorAll("button")].map(function(btn){
  console.log(btn);
  })

5.2、rest参数

  • 解构数组与对象(剩余运算)

  • rest 参数(形式为...变量名),rest运算符用于获取函数调用时传入的参数。

// function fn(a,b,c,d,...suibian){
// 	console.log(a,b,c,d,suibian);// 1 2 3 4 [5,6,7,8]
// }
// fn(1,2,3,4,5,6,7,8);

// function fn(...suibian){
// 	console.log(suibian);// [1,2,3,4,5,6,7,8]
// }
// fn(1,2,3,4,5,6,7,8);

* 和普通参数混合使用的时候,需要放在参数的最后

​```js
// 以下不允许
function fn(a,...my,b){

}
fn(1,2,3,4);
  • 函数的length属性,不包括 rest 参数
function fn(a,b,c,d,...my){
 
}
 
console.log(fn.name);// fn
console.log(fn.length);// 4

六、数组的扩展

6.1、Array对象的新方法

  • from:把伪数组转换成数组(可以使用数组的方法)
{
   // 1
   // function fn(){
   // 	// 转为真数组
   // 	const arr = Array.from(arguments);
   // 	arr.push(100);
   // 	console.log(arr);// [1,2,3,4,100];
   // }
   // fn(1,2,3,4);


   // 2
   const btns = document.querySelectorAll("button");
   // let arr2 = [];
   // btns.forEach(function(btn){
   // 	arr2.push(btn.innerText)
   // })
   // console.log(arr2);
   
   let arr2 = Array.from(btns).map(function (suibian) {
       return suibian.innerText;
   })
   console.log(arr2);
}
{
   // 可以实现对数组的复制(针对于简单数组为深复制,复杂数组为浅复制)
   // const arr = [1, 2, 3, 4];
   // const arr2 = Array.from(arr);
   // console.log(arr2, arr2 === arr);// [1, 2, 3, 4] false


   const arr = [1,{},2];
   const arr2 = Array.from(arr);
   console.log(arr === arr2,arr[1] === arr2[1]);
   arr2[1].userName = "zhangsan";
   console.log(arr[1].userName);// zhangsan
}
  • of:将一组数字转换成数组 弥补Array的不足
{
   // 不足:传递的参数代表的含义不同。
   // console.log(new Array());// []
   // console.log(new Array(10));// 定义了一个长度为10的数组,元素为empty
   // console.log(new Array(1,2,3,4,5,6,7));// [1,2,3,4,5,6,7]

   console.log(Array.of());// []
   console.log(Array.of(1));// [1]
   console.log(Array.of(1,2,3,4));// [1,2,3,4]
   console.log(Array.of("one","two","three"));
}

6.2、Array原型上的新增方法

  • copyWithin:数组实例的copyWithin()方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组
// const arr = [1,2,3,4,5];
// arr.copyWithin();
// console.log(arr);// [1,2,3,4,5]
 
// const arr = [1,2,3,4,5];
// // 复制的内容:1,2,3,4,5, 从下标1开始替换[1,1,2,3,4]
// // 操作完毕之后会将arr进行返回
// const arr2 = arr.copyWithin(1);// 从下标为1的元素开始进行覆盖。默认从下标0开始到长度-1复制
// console.log(arr,arr2,arr === arr2);// [1, 1, 2, 3, 4] [1, 1, 2, 3, 4] true
 
// const arr = [1,2,3,4,5,6];
// const arr2 = arr.copyWithin(3);// 复制出来的内容1 2 3 4 5 6
// console.log(arr2);// [1,2,3,1,2,3]


// const arr = [1,2,3,4,5,6];
// 第一个参数为替换位置下标
// 第二个参数是复制内容开始的下标,默认为0
// console.log(arr.copyWithin(3,2));// 复制的内容 3,4,5,6  结果:[1,2,3,3,4,5]

// const arr = [1,2,3,4,5,6];
// 第三个参数是复制结束的位置-1
// console.log(arr.copyWithin(3,2,4));// 复制的内容 3 4  结果[1,2,3,3,4,6]


const arr = [1,2,3,4,5,6,7,8,9];
console.log(arr.copyWithin(3,2,5));// 复制的内容 3,4,5 结果:[1,2,3,3,4,5,7,8,9]
console.log(arr.copyWithin(2,1,6));// 复制的内容 2 3 3 4 5 结果:[1,2,2,3,3,4,5,8,9] 
  • fill:使用固定值填充数组

    • fill方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去。
const arr = [1,2,3,4,5];
const arr2 = arr.fill(100);
console.log(arr2,arr,arr===arr2);// [100, 100, 100, 100, 100] [100, 100, 100, 100, 100] true

const arr3 = [];
console.log(arr3.fill(1));
console.log(new Array(10).fill(1));// [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  • fill方法还可以接受第二个(默认0)和第三个参数(默认数组的长度),用于指定填充的起始位置和结束位置。
const arr = [1,2,3,4,5];
// console.log(arr.fill("one",1));// [1, 'one', 'one', 'one', 'one']
console.log(arr.fill("one",1,3));// [1, 'one', 'one',4, 5]
  • entries()keys()values()

ES6 提供三个新的方法——entries()keys()values()——用于遍历数组。它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

const arr = ["one","two","three"];
// for(let item of arr.values()){
// 	console.log(item);
// }
// for(let item of arr){
// 	console.log(item);
// }
// for(let index of arr.keys()){
// 	console.log(index)
// }
// for(let item of arr.entries()){
// 	const [index,value] = item;
// 	console.log(item,index,value);
// }

for(let [index,value] of arr.entries()){
  console.log(index,value);
}
  • findfindIndex(记住)

数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined

{
 const arr = [
     {
         id:1,
         bookName:"水浒传"
     },{
         id:2,
         bookName: "西游记"
     },{
         id:3,
         bookName: "三国演义"
     },{
         id:4,
         bookName: "红楼梦"
     }
     ,{
         id:5,
         bookName: "西游记"
     }
 ];
 // find:接收一个回调函数
 // 回调函数一旦返回真,那么后续的遍历不会执行。
 // 会将第一个满足条件的元素返回,如果没有满足条件 的元素返回的是undefined
 // const bookInfo = arr.find(function(item){
 // 	return item.bookName === "西游记";
 // })
 // if(bookInfo){
 // 	console.log("有")
 // }else{
 // 	console.log("无")
 // }

 // console.log(arr.some(function(item){
 // 	return item.bookName === "西游记1"
 // }))

 // findIndex:接收一个回调函数
 // 回调函数一旦返回true,那么后续的遍历不会执行
 // 会将第一个满足条件元素的下标进行返回,如果找不到满足条件的元素,那么返回-1
 console.log(arr.findIndex(function(item){
     return item.bookName === "西游记1";
 }))
}
  • includes:(记住)

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

    const arr = [1,2,3,4];
    console.log(arr.includes(4));// true
    console.log(arr.includes(40));// false
    
  • flat

    • 数组的成员有时还是数组,Array.prototype.flat()用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。

      • flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1
      // const arr = [1,2,[3,4,5],6,7,8];
      // console.log(arr.flat(),arr);// [1,2,3,4,5,6,7,8]
             
      // const arr = [1,2,[3,[4,5,6],7],8];
      // console.log(arr.flat());// [1,2,3,[4,5,6],7,8];
      // console.log(arr.flat().flat());// [1,2,3,4,5,6,7,8];
      // console.log(arr.flat(1));// [1,2,3,[4,5,6],7,8];
      // console.log(arr.flat(2));// [1, 2, 3, 4, 5, 6, 7, 8];
      
      • 如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数
      const arr = [1,2,[3,[4,5,6],7],8];
      console.log(arr.flat(Infinity));// [1, 2, 3, 4, 5, 6, 7, 8]
      

七、函数的扩展

7.1、 函数参数默认值

7.1.1、ES5默认参数

ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。

function fn(num){
 if(num === undefined) num = 1;
 console.log(num);
}
fn();
7.1.2、ES6 默认参数

ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

// function fn(num=1){
// 	console.log(num);// 1
// }
// fn();

7.2 rest参数(详见5.2)

7.3 箭头函数

7.3.1、什么是箭头函数

ES6 允许使用“箭头”(=>)定义函数。

// 1
function fn(a, b) {
 return a + b;
}

console.log(fn(1, 2));// 3

// 2
const fn2 = function (a, b) {
 return a + b;
}
console.log(fn2(10, 20));// 30

// 3
const fn3 = new Function("a", "b", "return a+b");
console.log(fn3(100, 200));// 300

// 4- 箭头函数
const fn4 = (a, b) => {
 return a + b;
}
console.log(fn4(9,99));// 108
7.3.2、箭头函数的写法

箭头函数分为以下几种情况

  • 只有一个参数,括号可以省略
{
   // const fn = (a) => {
   // 	return 100 + a;
   // }
 
   // 上方函数的括号可以省略
   // const fn = a => {
   // 	return 100 + a;
   // }
   // console.log(fn(1));// 101
 
   // 如果参数为多个或无参数括号不能省略
   // 无参数,不可以省略括号
   const fn = ()=>{
 
   }
   // 多个参数,不可以省略括号
   const fn2 = (a,b,c) => {
 
   }
}
  • 函数体是一条语句的时候,可以省略花括号,会将该语句的结果进行返回(return 省略不写)
{
   const fn = () => {
       return 1;
   }
   // 简写为:
   const fn2 = () => 1;
   console.log(fn());// 1
   console.log(fn2());// 1
}
{
   const fn = (a) => {
       return a;
   }
   const fn2 = a => a;
   console.log(fn(100));// 100
   console.log(fn2(100));// 100
 
}
  • 没有参数或者多个参数的时候,参数的括号不能省略

  • 当函数体不是一句话的时候,花括号 不可以省略

{
   const fn = ()=>{
       let a = 1;
       console.log(a);
   }
}
  • 如果函数体内只有一行代码,该行代码返回的是对象的话,可以使用括号。
// 1
// const fn = function(){
// 	return {
// 		a:1,
// 		b:2
// 	}
// }
 
// 2- 箭头函数
const fn = ()=>{
   return ({
       a:1,
       b:2
   })
}
// 3- 箭头函数简写
const fn2 = ()=>({
   a:1,
   b:2
})
7.3.3、箭头函数的注意事项
  • 关于this

    箭头函数没有自己的this,箭头函数内部的this并不是调用时候指向的对象,而是定义时指向的对象

    // window.userName = "window->userName";
    // const obj = {
    // 	userName:"obj->userName",
    // 	fn:function(){
    // 		// this与调用时查看
    // 		// 1- 是否有显式绑定this. call apply bind
    // 		// 2- 是否有隐式绑定 . 左侧
    // 		console.log(this===obj,this.userName)
    // 	},
    // 	run:()=>{
    // 		console.log(this.userName);
    // 	}
    // }
    // obj.fn();// obj
    // obj.fn.call(window);// window
    // obj.fn.apply(window);// window
    // obj.fn.call();// window
    // obj.fn.apply();// window
    // obj.fn.bind()();// window
    //
    // obj.run();// window
    
    // 2-示例
    // const btns = document.querySelectorAll("button");
    // btns.forEach(function (btn){
    // 	btn.onclick = function(){
    // 		console.log(this);// btn
    // 	}
    // })
    
    // btns.forEach(function (btn){
    // 	btn.onclick = ()=>{
    // 		console.log(this);// {a:1,b:2}
    // 	}
    // }.bind({a:1,b:2}))
    
    // btns.forEach((btn)=>{
    // 	btn.onclick = ()=>{
    // 		console.log(this);// window
    // 	}
    // })
    
    // 3- 示例
    function Tag(){
      this.btns = document.querySelectorAll("button");
      this.init();
    }
    window.btns = document.querySelectorAll("button");
    Tag.prototype.init = ()=>{
      this.btns.forEach(btn=>{
          btn.onclick = ()=>{
              console.log(this);// btn
          }
      })
    }
    const tag = new Tag();
    
  • 箭头函数不能用于构造函数,也就是不能使用new关键字调用

const Tag = ()=>{

}
// new Tag();// ypeError: Tag is not a constructor
console.log(Tag.prototype);// undefined
// function Box(){
//
// }
// const obj = new Box();
// console.log(obj.constructor === Box);// true
// console.log(obj.__proto__.constructor === Box);// true
// console.log(Box.prototype.constructor === Box);// true
// console.log(Box.constructor === Function);// true

- 箭头函数没有arguments对象


const fn = () => {
// ReferenceError: arguments is not defined
// console.log(arguments);
}
fn();
  • 箭头函数使用call apply bind,无法提定this
const obj = {
   a: 1,
   b: 2
}

const fn = () => {
   console.log(this === obj);
}
fn.call(obj);// false
fn.apply(obj);// false
fn.bind(obj)();// false

八、对象的扩展

8.1、对象的简写

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

// 未简写:
// let a = 100;
// const obj = {
// 	a:a,
// 	b:2,
// 	fn:function(){
// 		console.log(this.a,this.b);
// 	}
// }
// console.log(obj.a,obj.b);// 100 2
// obj.fn();// 100 2

// 简写:
let a = 100;
const obj = {
     a,// 将变量a的名字作为属性名,变量a的值作为属性值。
     b:2,
     // 可以省略:function
     fn(){
         console.log(this.a,this.b);
     },
     run:()=>{
         console.log(this.a,this.b);// undefined undefined
     }
}
console.log(obj.a,obj.b);// 100 2
obj.fn();// 100 2
obj.run();

8.2 、属性名表达式

JavaScript 定义对象的属性,有两种方法:点运算符和中括号运算符

// const obj = {
// 	a:1
// }
// obj.b = 2;
// obj["c"]=3;
// console.log(obj);

但是,如果使用字面量方式定义对象(使用大括号),在 ES5 中只能使用标识符,而不能使用变量定义属性。

也就是说在ES5中 key/value key是固定不变的,在ES6中,支持属性表达式,支持key发生变化

let b = 2;
const obj = {
 a:1,
 [b]:2,// 将变量b的值作为key(属性名),
 "#$%^&*(":3
}
// b = 3;
console.log(obj["2"]);// 2
console.log(obj[b]);// 2
console.log(obj["#$%^&*("]);// 3
console.log(obj);// {2:2,a:2}

8.3、 对象的扩展运算符 …(见5.1)

8.4 对象新增的方法

8.4.1、Object.is()

判断对象是否相等 相当于===,修复NaN不等自己的问题

console.log(1 == "1");// true
console.log(1 === "1");// false
const obj = {};
console.log(obj.a === undefined);// true
console.log(null === null);// true
console.log(NaN === NaN);// false

console.log(Object.is(NaN,NaN));// true
console.log(Object.is(1,"1"));// false
console.log(Object.is(1,1));// true
8.4.2、合并方法Object.assign()
8.4.3、Object.keys
8.4.4、Object.values

九、Math的扩展

9.1、指数运算符

  • 在Math中提供了 pow的方法 用来计算一个值的n次方
  • ES11 提出了新的方法求一个值的n次方 那就是 ** 操作符
2**4 // 16

9.2、进制写法

  • ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b0o表示。
0b11110  // 30
0o12 // 10

9.3、Math的新增方法

  • Math.trunc()方法会将数字的小数部分去掉,只保留整数部分
Math.trunc(123.456) // 123
  • Math.sign() 判断一个数字的正数还是负数 还是0 或者是NaN
Math.sign(123.456)     //1 
Math.sign(-123.456)   // -1
Math.sign('qwe1')       // NaN
Math.sign('') 		    // 0
  • Math.sqrt()平方根
Math.sqrt(16) // 4
  • Math.cbrt()立方根
Math.cbrt(27)  // 3
  • Math.hypot() 求所有参数平方和的平方根

十、Number的扩展

  • Number.isFinite(i) : 用来检查一个数值是否为有限

  • Number.isNaN(i) : 判断是否是NaN

  • Number.isInteger(i) : 判断是否是整数

  • Number.parseInt(str) : 将字符串转换为对应的数值

十一、新增数据类型

11.1、Symbol

11.1.1、什么是Symbol

ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法,新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是ES6引入Symbol的原因。

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型

11.1.2、Symbol的使用
  • Symbol 值通过Symbol函数生成。

    • 这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突
11.1.3、Symbol表示独一无二的值
11.1.4、Symbol的注意事项
  • Symbol中传入的字符串没有任何意义,只是用来描述Symbol

    • Symbol不能使用New调用

    • 类型转换的时候,不能转数字

    • 如果把Symbol当作一个对象的属性和方法的时候,一定要用一个变量来储存,否则定义的属性和方法没有办法使用

  • for in 不能遍历出来,可以使用Object.getOwnPropertySymbols方法来拿;

11.2、BigInt

  • JavaScript 所有数字都保存成 64 位浮点数,这给数值的表示带来了两大限制。一是数值的精度只能到 53 个二进制位(相当于 16 个十进制位),大于这个范围的整数,JavaScript 是无法精确表示的,这使得 JavaScript 不适合进行科学和金融方面的精确计算。二是大于或等于2的1024次方的数值,JavaScript 无法表示,会返回Infinity

    • 引入了一种新的数据类型 BigInt(大整数),来解决这个问题。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。

    • 为了与 Number 类型区别,BigInt 类型的数据必须添加后缀n

    • BigInt 与普通整数是两种值,它们之间并不全等。

  • typeof运算符对于 BigInt 类型的数据返回bigint

十二、新增数据结构

12.1、Set

12.1.1、什么是Set
  • ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
    • Set本身是一个构造函数,用来生成 Set 数据结构。

    • Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化

12.1.2、 Set的属性及方法
  • size 返回Set的长度
  • add 添加某个值,返回 Set 结构本身。
  • delete 删除某个值,返回一个布尔值,表示删除是否成功。
  • has 返回一个布尔值,表示该值是否为Set的成员
  • clear 清除所有成员,没有返回值。
  • keys():返回键名的遍历器,由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员

12.2、Map

12.2.1、什么是Map
  • JavaScript 的对象(Object),本质上是键值对的集合,但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

    • 为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
12.2.2、Map的属性和方法
  • size属性返回 Map 结构的成员总数。
  • set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。set方法返回的是当前的Map对象,因此可以采用链式写法。
  • get方法读取key对应的键值,如果找不到key,返回undefined
  • has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
  • delete方法删除某个键,返回true。如果删除失败,返回false
  • clear方法清除所有成员,没有返回值。
  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历 Map 的所有成员。

十三、iterator

13.1、什么是iterator

  • JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了MapSet。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是MapMap的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
  • 遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
  • Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。

13.2、iterator

  • ES6中,只要一种数据结构具有了Symbol.iterator属性,那么就认为是可以迭代的

  • 在ES6中,很多数据结构都部署了iterator接口(Array,set,Map,string)

  • 应用场景:

    • 解构赋值的时候默认调用iterator接口

    • 扩展运算符使用的时候页默认调用iterator接口

    • for of 使用的是iterator接口

    • 对象是没有部署Iterator接口

十四、Promise

十五、ES6模块化

十六、class

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值