ES6重要知识点总结

ES6

1 ES6入门

阮一峰书籍推荐:https://es6.ruanyifeng.com/#docs/reference

1.1 简介

ECMAScript标准简称为ES6也称为ES2015,规定以后的ECMAScript标准每一年一更,统一以年份命名(每年的六月份)

1.2 块级作用域

通过块级声明的变量无法被代码块外部访问,这种就称为块级作用域,也成为语法作用域

块级作用域可以在函数内部和代码块{}内部创建

1.3 let和const

{
    var a=2;

    let b=10;
     变量b只能在代码块内访问
    console.log(a)//2
    console.log(b)//10
}

console.log(a)//2
console.log(b)//b is not defined

let特点:

  • let和const不存在变量提升,原因let和const之前的区域叫做暂存性死区,var的变量存在变量提升
  • let和const声明的变量不再属于window,不能通过window.变量名访问,var声明的变量属于window
  • 使用块级作用域不能在同一级中重复声明变量(let声明的变量不能重复)

const特点:

  • const和let,除了const是声明常量外,其他的特点和let一样
  • const声明的常量只能在声明的时候赋值
  • const声明的常量不可以修改

练习:实现点击输出当前下标

*{margin: 0;padding: 0;}
ul{list-style: none; margin: 50px auto; width: 200px;}
li{
    width: 200px;
    height: 50px;
    background-color: rgb(126, 235, 116);
    margin: 10px 0;
}
<ul>
    <li></li>
    <li></li>
    <li></li>
</ul>

ES5:

var li=document.getElementsByTagName('li');
for(var i=0;i<li.length;i++){
    li[i].index=i;
    li[i].onclick=function(){
        console.log(this.index)
    }
}

ES6:

//普通函数版
var li=document.getElementsByTagName('li');
console.log(li)
for(let i=0;i<li.length;i++){
    li[i].onclick=function(){
        console.log(i)
    }
}

//箭头函数版
var li=document.getElementsByTagName('li');
console.log(li)
for(let i=0;i<li.length;i++){
    li[i].onclick=()=>{
        console.log(i)
    }
}

2 ES6函数新增特性

2.1带默认值的函数

JavaScript函数最大的特性就是在传递参数时,参数的个数不受限制,为了函数的健壮性,一般在函数内部做默认值处理

ES6中从语法层面新增了‘默认值’的支持(默认值可以为数字、字符串、表达式甚至为函数)

ES5:

function fun(a,b){
    a= a || 10;
    b= b || 30;
    console.log(a,b)//10 30
}
// fun(10,30)//10 30
fun(0,0)//出现bug,得到10,30

ES6:

function demo(a=10,b=30){
    console.log(a,b)//10 30
}
// fun(10,30)//10 30
demo(0,0)//0,0

2.2 默认值影响arguments

ES5中arguments用于接收所有传入的实参,返回的是一个数组

ES5:

//非严格模式下,形参重新赋值,会影响arguments里面的值
function fun1(a,b){
    console.log(arguments)//[3,6]
    console.log(arguments[0]===a)//true
    console.log(arguments[1]===b)//true

    a=33;
    b=20;
    console.log(arguments[0]===a)//true
    console.log(arguments[1]===b)//true
    console.log(arguments)
}
fun1(3,6)

//严格模式
function fun2(a,b){
    //使用严格模式,形参重新赋值,不会影响arguments里面的值
    'use strict'
    console.log(arguments)
    console.log(arguments[0]===a)//true
    console.log(arguments[1]===b)//true

    a=33;
    b=20;
    console.log(arguments[0]===a)//false
    console.log(arguments[1]===b)//fasle
    console.log(arguments)
}
fun2(3,6)

fun1()结果:

ES6重要知识点总结

fun2()结果:

ES6重要知识点总结

ES6:

//在ES6中若有参数默认值,不管是在严格模式还是非严格模式,都和ES5中的严格模式相同
function fun3(a,b=1){
    console.log(arguments)
    console.log(arguments[0]===a)//true
    console.log(arguments[1]===b)//true

    a=33;
    b=20;
    console.log(arguments[0]===a)//false
    console.log(arguments[1]===b)//false
}
fun3(3,6)

fun3()结果:

ES6重要知识点总结

注:

“use strict” 的目的是指定代码在严格条件下执行。

严格模式下你不能使用未声明的变量。

2.3 默认参数为表达式

参数的默认值可以是一个表达式或者函数的调用

function getValue(){
    return 5;
}
function add(first,seconed=getValue()){
    return first+seconed;
}
var res = add(1)
console.log(res)//6

//注意:getValue()只会在调用add函数且不传入第二个参数时才会去调用
//由于默认值可以是表达式,所以我们可以使用前面的参数作为后面参数的默认值
//反之则不成立(不能采用后面的参数定义表达式作为参数默认值)
function add(first=2,seconed=first+1){
    return first + seconed;
}

var res = add(3);
console.log(res)//7

var res = add();
console.log(res);//5

2.4 剩余参数(重点)

ES6中提供了一种更加便捷处理未命名参数的方法,叫做剩余参数
语法:
    function fun(a,...b){
        [剩余参数用三个点接收,多余的参数则被放到数组b中]
    }
function run(a,b,...c){

    //arguments接收的是所有传入的实参
    console.log(arguments)//[1, 2, 3, 4, 5, 6, 7, 8]

    //...剩余参数只接收剩余的形参
    console.log(a,b)//1 2
    console.log(c)// [3, 4, 5, 6, 7, 8]
}
run(1,2,3,4,5,6,7,8)

注意:

  • 函数最多只能有一个剩余参数,且该参数必须放置在所有形参的最后
  • 虽然有剩余参数,arguments仍然存在
  • 剩余参数是在**“函数声明的时候”**出现

2.5 扩展运算符(重点)

1 扩展运算符拆散数组或对象

var arr=[1,2,3,4,5,6]
//Math.max()只能接收一个一个的数
var res=Math.max(1,2,3,4,5)
console.log(res)//6

//ES5中需要通过apply切换对象取得最大值
var res =Math.max.apply(Math,arr)
console.log(res)//6

//ES6中...扩展运算符可以获得数组中的一个一个的数,相当于拆散了数组或对象
console.log(...arr)//1 2 3 4 5 6
console.log(Math.max(...arr))//6

2 扩展运算符连接两个数组

var arr1=['胡桃','七七'];
var arr2=[1,2,3,4,5]

//ES5
var newArr=arr2.concat(arr1)
console.log(newArr)//[1, 2, 3, 4, 5, "胡桃", "七七"]

//ES6
var arr3=[1,2,3,4,5,...arr1]
console.log(arr3)//[1, 2, 3, 4, 5, "胡桃", "七七"]

3 扩展运算符继承的使用

 var People={
            nation:'中国',
            city:'北京'
        }
 var student={
     //继承父类
     ...People
 }
console.log(student)//{nation: "中国", city: "北京"}

People.city='上海'
console.log(People)//{nation: "中国", city: "上海"}
console.log(student)//{nation: "中国", city: "北京"}


var People={
    nation:'中国',
    city:'北京',
    foods:['烤鸭','抄手','小面']
}
var student={
    //继承父类
    ...People
}
People.foods.push('刀削面')
console.log(People.foods)// ["烤鸭", "抄手", "小面", "刀削面"]
console.log(student.foods)// ["烤鸭", "抄手", "小面", "刀削面"]

通过上面的实例可以看出,…扩展运算符的继承是实现的浅拷贝操作

2.6 结构赋值(重点)

ES6允许我们按照一定的模式从数组或者对象中提取变量进行赋值,被称为结构赋值

本质上,结构赋值属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值

//ES5的赋值,分别取出数组的值,赋值给对应的变量
var arr=[1,2,3];
var a=arr[0];
var b=arr[1];
var c=arr[2];
console.log(a,b,c)

//ES6数组的结构赋值主要依据相同下标进行赋值
var [a,b,c]=[10,20,30];
console.log(a,b,c);//10 20 30

var [d,,e]=[10,20,30]
console.log(d,e);//10 30
//对象的结构赋值主要查看属性名和方法名
//只有当变量名和属性名同名时,才能取到正确的值,和先后顺序无关
var People={
    nation:'中国',
    city:'北京',
    foods:['烤鸭','抄手','小面']
}

var {nation,city}=People
console.log(nation,city)//中国 北京

var {city,nation}=People
console.log(nation,city)//中国 北京

//结构赋值常见的使用方式
function demo({city}){
    //相当于{city}=People
    console.log(city)//北京
}
demo(People)

3 箭头函数(重点)

3.1 语法

ECMAScript6 允许使用箭头 =>定义函数,语法如下

(arg1,arg2...)=>{
    函数体
}

示例1:

  • 当箭头函数的形参只有一个时,包含形参的()可以省略,其他情况都不能省略
  • 当箭头函数后只有一行代码且不加大括号{},则自带return 功能
//普通函数
//ES5
var fun=function(){
    console.log(111)
}
//ES6
var fun=()=>{
    console.log(111)
}
fun()
//带参数的函数
var fun1=function(a){
    return a
}
var fun1=(a)=>{
    return a
}
//当箭头函数的形参只有一个时,包含形参的()可以省略,其他情况都不能省略
//当箭头函数后只有一行代码且不加大括号{},则自带return 功能 
var fun1=a=>a

var res=fun1(3)
console.log(res)//3

示例2:

特殊情况:return返回值为一个对象

//特殊情况:return返回值为一个对象

//ES5
var fun2=function(){
    // var obj={
    //     name:'胡桃',
    //     age:16
    // }
    return {
        name:'胡桃',
        age:16
    };
}

//ES6
var fun2=()=>{
    // var obj={
    //     name:'胡桃',
    //     age:16
    // }
    return {
        name:'胡桃',
        age:16
    };
}

//特殊情况,得在对象{}之外再加一个()
var fun2=()=>({ name:'胡桃',age:16})

var res=fun2();
console.log(res);//{name: "胡桃", age: 16}

示例3:

使用箭头函数自执行

//使用箭头函数自执行

//ES5
(function(){
    console.log('匿名函数')
})();

//ES6
(()=>{
    console.log('匿名函数')
})();

3.2 箭头函数中无this绑定

在ES5中this的绑定是一个比较麻烦的问题,稍微不注意就达不到想要的效果,因为在ES5中this的绑定和定义的位置无关,只和其调用的位置有关

ES5中this指代问题:

  • 在普通函数中,this指代全局对象window
  • 在普通对象中,this指代当前对象
  • 在构造函数中,this指代实例化对象
  • 在apply、call、bind切换对象时,this指代切换后的对象

箭头函数中没有this的绑定(并不是说ES6没有this),this的定义只和定义的作用域有关,和调用的位置无关

// ES5的写法
btn.onclick = function(){
    // 定时器  2s后输出
    setTimeout(function(){
        console.log(this)//window
    },2000)

    // ES6 箭头函数
    btn.onclick = function(){
        setTimeout(()=>{
            console.log(this);//btn按钮
        },2000)
    }

箭头函数可以让this指向固定化,这样有利于面向对象封装回调函数

//构造函数
function Dog(name,color){
    this.name = name;
    this.color = color;
}

Dog.prototype.doSomething = function(){
    
    document.onclick =()=>{
    	console.log(this)//Dog
    	console.log(this.color)//yellow
    }
}
			
var dog = new Dog('大黄','yellow');
console.log(dog)
dog.doSomething()//yellow

总结:

1、注意箭头函数中this指向固定化,并不是因为箭头函数内部有绑定this,实际原因时箭头函数内根本没有绑定this,导致函数内部的this就是外部代码块的this

2、箭头函数作为一个用完就扔的函数,不能作为构造函数使用,也就是说不能使用new的方式来使用箭头函数

3、由于箭头函数中的this与函数的作用域无关,所以不能使用call、apply、bind来重新绑定this

4、箭头函数内没有自己的arguments对象,但是箭头函数内可以使用外部的arguments对象

4 对象的扩展功能

在js中,几乎所有的类型都是对象,所以使用好对象,对提高js性能很重要

4.1 对象类别(了解)

普通对象(ordinary object)拥有js所有的默认行为

特异对象(exotic object)某些内部行为与默认有所差异

标准对象(stabdard object)是ES6中定义的对象,例如Array Date等,他们可能是普通对象也可能是特异对象

内置对象(built-in object)指js的运行环境开始运行时已存在的对象,标准对象均为内置对象

4.2 字面量语法扩展(重点)

4.2.1 简化属性的初始化

var name ='七七'
var age=16

var obj={
    name:name,
    age:age
}
console.log(obj)//{name: "七七", age: 16}

//改进
var name ='七七'
var age=16

var obj={
    name,
    age
}
console.log(obj)//{name: "七七", age: 16}


注意:在ES6中,若对象属性名和本地变量名相同时,赋值可以省略冒号和值,直接写属性

当对象字面量中属性只有属性名时,js引擎会在其作用域之内寻找是否有和属性名同名的变量,简写可以让对象的字面量更加简洁。

4.2.2 对象方法的简写

var name ='七七'
var age=16

var obj={
    name,
    age,
    //对象方法简写
    play(){
        console.log('僵尸')
    }
}
obj.play()//僵尸

4.2.3 属性名提前

var key1='adas_sd'
var key2='aacc_a'

var obj={
    key1:12312,
    key2:123456,
    
	//变量名作为属性名  需要加上中括号
    [key1]:12312,
    [key2]:123456,   
}
console.log(obj)//{key1: 12312, key2: 123456, adas_sd: 12312, aacc_a: 123456}

4.3 对象中新增的方法

4.3.1 Object.is()

Object.is()判断两个对象是否相等,该方法是对全等(===)的怪异行为的补偿,只有在两者的类型和值都相等时才会判断为相等

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

console.log(NaN == NaN)//false
console.log(NaN === NaN)//false
console.log(Object.is(NaN,NaN))//true

一般情况下Object.is()的效果和===(全等)是相同,他们的区别就是在怪异情况的判断 +0 -0 NaN

4.3.2 Object.assign()

使用Object.assign()主要是为了简化对象的混合(mixin),混合指的将一个对象引入到另一个对象的属性或者方法(拷贝)

var obj={
    name:'胡桃',
    age:16,
    love:['七七','钟离','烟绯']
}

var newObj={}

//obj对象复制给newObj对象
Object.assign(newObj,obj)
console.log(newObj)//{name: "胡桃", age: 16, love: Array(3)}


obj.love.push('凝光')
console.log(obj.love)//["七七", "钟离", "烟绯", "凝光"]
console.log(newObj.love)//["七七", "钟离", "烟绯", "凝光"]
//以上说明Object.assign() 方法为浅拷贝


//Object.assign()可以同时拷贝多个对象
var obj2={
    name:'甘雨',
    love:'雷军'
}

//newObj有多个提供者
Object.assign(newObj,obj,obj2)

console.log(obj2)//{name: "甘雨", love: "雷军"}
console.log(newObj)//{name: "甘雨", age: 16, love: "雷军"}
 多个提供者,意味着后面的提供者若同名则覆盖前面的提供者的属性

注意:

Object.assign()的这种copy(拷贝)是浅拷贝

浅拷贝指的是拷贝的属性的属性值不是基本数据类型(数组\对象)时

拷贝只是copy该对象的内存地址

5 字符串新增功能

5.1 查找字符串

在ES5中字符串的查找,都是使用indexOf() lastIndexOf()

ES6新增了三个方法来查找字符串

includes(text,index) 查找字符串是否在文本中,返回boolean值。存在->true  不存在->false
startsWith(text,index)文本是否以指定的字符开头,返回boolean值  
endsWith(text,length)文本是否以指定的字符结尾,返回boolean值  

注意:
length代表总长度从1开始计算
index代表下标从0开始计算
var str ='大丘丘病了二丘丘瞧,三丘丘采药,四丘丘熬';

var res=str.includes('大丘丘');
console.log(res)//true
var res=str.includes('大丘丘',2);//从2下标开始查找
console.log(res)//false

var res=str.startsWith('大丘丘');
console.log(res)//true
var res=str.startsWith('二丘丘',5);
console.log(res)//true


var res=str.endsWith('大丘丘');
console.log(res)//false
var res=str.endsWith('大丘丘',3);
console.log(res)//true

5.2 repeat()方法

//repeat(n) 重复前面字符串的次数
var str='胡桃';
var res=str.repeat(3)
console.log(res)//胡桃胡桃胡桃

5.3 字符串的模板字面量(重点)

模板字面量主要是ES6针对js的如下功能的改进:

多行字符串

基本的字符串格式化:将字符串中的变量转换为值的能力

转义HTML:将字符串进行转义并使用安全得插入Html的能力

1.语法

使用一对反括号 `` (Tab键正上方) 来表示模板字面量

2.多行字符串

//字符串的模板字面量 ``

//报错
// var str='胡桃
// 甘雨
// 钟离'

var str=`胡桃
甘雨
钟离`
console.log(str)//按原文本格式输出

3.字符串的置换(重点)

//字符串的置换
var obj={
    name:'胡桃',
    age:16,
    area:'璃月'
}

//ES5 字符串拼接
var str=obj.name+'今年'+obj.age+'岁,住在'+obj.area
console.log(str)//胡桃今年16岁,住在璃月

//ES6 模板字面量
var str=`${obj.name}今年${obj.age}岁,住在${obj.area}`
console.log(str)//胡桃今年16岁,住在璃月

4.模板标签

模板字面量真正的强大之处在于模板标签,一个模板标签可以被转换为模板字面量并作为最终值返回(标签必须在模板之前指定)

模板标签其实并不是模板而是一种函数的调用的特殊形式,标签指的就是函数,紧跟在后面的模板字符串就是他的参数

//模板标签
alert `璃月人`//等价于 alert('璃月人')

5.自义定模板标签

function myTag(str,...value){
    //str 拿到除了变量以外的字符
    console.log(str)//["", "今年", "", raw: Array(3)]

    //剩余参数拿到所有字符串中的变量,以数组的方式返回
    console.log(value)//["胡桃", 18]
}
var name = '胡桃'
var age = 18
myTag`${name}今年${age}`;

ES6重要知识点总结

6 新的基本类型 Symbol

ES5中有六种数据类型:

  • number数值类型
  • string字符串类型
  • boolean布尔类型
  • undefined未定义类型
  • null空类型
  • object对象类型(function)

ES6新增了一种数据类型Symbol

解决:在ES5中我们对象的属性为字符串,容易被重写。没有办法创建私有属性,只能通过封装。Symbol创建一个独一无二的值

6.1 创建Symbol

Symbol在基本数据类型中比较特殊,需要通过全局函数Symbol创建

//创建Symbol
var names= Symbol();
console.log(typeof name)//symbol

var obj={
    [names]:'胡桃',
    age:16
}

console.log(obj)//{age: 16, Symbol(): "胡桃"}
var a1=Symbol();
var a2=Symbol();
console.log(a1==a2)//false
console.log(a1===a2)//false

var obj={
    [Symbol()]:'独一无二'
}
console.log(obj)//{Symbol(): "独一无二"}
//此时Symbol()重新创建了另一个独一无二的值,则obj内该属性未被赋值,则为undefined
console.log(obj[Symbol()])//undefined

在创建symbol时,括号内允许传入字符串,该字符串仅为了区分symbol,没有任何实际作用

var s1 = Symbol('七七')
var s2 = Symbol('七七')
console.log(s1 === s2)//false

注意:s1 s2都是一个独一无二的值
若属性名使用symbol类型,可以保证属性名都是独一无二的,不会与其他属性名冲突

6.2 识别Symbol

symbol属于基本数据类型,可以使用typeof操作符辨别是否为symbol。

如果在控制台直接输出symbol变量,那么不好区分,建议在创建symbol变量时,添加参数(字符串),用于描述创建的symbol作为区分

6.3 Symbol作为对象属性(重点)

//symbol作为对象的属性
var user=Symbol('user');
var age=Symbol('age');

//方法一
var person={
    // 变量名作为属性   需要添加中括号
    [user]:'胡桃'
}
console.log(person)//{Symbol(user): "胡桃"}

//方法二
person[age]=16
console.log(person)//{Symbol(user): "胡桃", Symbol(age): 16}

var sex;
person[sex]='女'
for(var key in person){
    console.log(person[key])//女
    console.log(`属性:${person[key]},属性值:${person[key]}`)//属性:女,属性值:女
}//以上例子说明:Symbol作为属性名时,不能采用for...in 或者for...of遍历

注意:

1、symbol作为对象的属性时,只能使用[]去添加或访问,不能使用点语法

2、symbol作为对象属性名使用时,该属性还是公有属性,不是私有属性。但此时无法通过for…in 或者for…of遍历

6.4 Symbol属性名的遍历

//遍历Symbol Object.getOwnPropertySymbols():将所有对象中的symbol属性以数组方式返回
var res=Object.getOwnPropertySymbols(person)
console.log(res)//[Symbol(user), Symbol(age)]
console.log(res[0])//Symbol(user)
console.log(person[res[0]])//胡桃

//Reflect.ownKeys():将所有对象中的属性以数组方式返回
var keys=Reflect.ownKeys(person);
console.log(keys)//["undefined", Symbol(user), Symbol(age)]

说明:由于Symbol的值作为属性名时,不会被常规方法遍历到(for…in for…of),我们利用该特性,为对象创建一些非私有但是希望只用于内部的方法

6.5 Symbol.for()和Symbol.keyFor()的使用

Symbol.for(字符串):每次创建时会在全局环境中搜索以该字符串作为参数的Symbol的值,若搜到则返回该Symbol,若搜索不到才创建一个Symbol,并把它注册到全局环境中

//Symbol和Symbol.for的区别

var a1=Symbol('胡桃')
var a2=Symbol('胡桃')
console.log(a1==a2)//false

//Symbol.for()每次创建都会在全局环境中搜索以该字符串作为参数的Symbol是否存在,若存在则直接返回已创建的Symbol,不存在则重新创Symbol,并向全局进行注册

var b1=Symbol.for('七七')
var b2=Symbol.for('七七')
console.log(b1==b2)//true

//Symbol.keyFor(symbol)返回一个已注册到全局的symbol的key
//只有注册的Symbol才会返回字符串
var res=Symbol.keyFor(b1)
console.log(res)//七七

Symbol.for()和Symbol()的区别:

1、Symbol.for()对同样的字符串每次得到的结果肯定一样,Symbol()则不会有相同的结果,每次都会新创建。

2、Symbol()每次都会创建一个全新的Symbol,且不会向全局注册;Symbol.for()只有在全局找不到时才创建新的Symbol,并注册到全局

6.6 Symbol总结

//1.创建独一无二的值
//2.给对象属性添加唯一值,先创建并赋值,加上[]
//3.作为对象属性,不能被for ...in遍历到
//4.Symbol每次创建不会注册到全局,Symbol.for()先查找再注册

7 Set

set本身是一个构造函数

//创建
var set =new Set()
//添加
set.add('胡桃')
//长度
console.log(set.size)

7.1 创建Set集合并添加元素

var set=new Set();
console.log(set)//Set(0)
console.log(typeof set)//object

//添加元素 add()
set.add('胡桃')
console.log(set)//Set(1) {"胡桃"}

//set集合长度
console.log(set.size)//1

7.2 Set不能添加重复元素

set.add('a');
console.log(set);//{"a", "b"}
console.log(set.size);//2

注意:set是通过Object.is()方法判断两个元素是否相等(但是判断+0 -0的时候用===判断)

set.add(+0);
set.add(-0);
console.log(set)//{"a", "b", "c", 0}

特殊情况:

// 特殊情况,数组、对象这种引用类型 每次添加都是指向不同的内存空间
console.log(set.size)//1

set.add([])
console.log(set.size)//2
set.add([])
console.log(set.size)//3

7.3 数组去重

var arr=[2,3,5,6,2,5,3]
var set =new Set(arr);
console.log(set)//[2,3,5,6]

7.4 判断某值是否在Set中

// 判断Set中是否存在某一个值  has()
var arrSet = new Set([2,3,4])
console.log(arrSet.has(5))//false
console.log(arrSet.has(2))//true

7.5 删除Set中的值

delete(需要删除的值)

clear()清空所有的值

var set= new Set([1,2,5,3,6,4])

//删除指定的值
set.delete(1)
console.log(set)//{2,5,3,6,4}

//清空所有的值
set.clear()
console.log(set)//{}

7.6 Set遍历

Set遍历智能使用隐式迭代,也就是forEach

补充知识点:
数组遍历(迭代):
    显示迭代  for循环
    隐式迭代  forEach
    
语法:
遍历的数组.forEach(function(val,key,ownerArr){
    //forEach中的形参不需要手动传入
     参数一:val代表遍历到的元素的值
    参数二:数组的键(下标)  但是对于Set类型,第二个参数和第一个的值相同
    参数三:当前遍历的整个对象
})
set.forEach(function(val,key,ownARR){
    console.log(key,val,ownARR)
})//输出的结果没有下标,所以不能通过for遍历

//改为箭头函数
set.forEach((val,key)=>{
    console.log(`key为:${key},值为:${val}`)
})//输出的结果没有下标,所以不能通过for遍历

ES6重要知识点总结

7.7 将Set转为数组(重点)

数组转换为Set:创建Set时把数组当作一个参数传入

Set转换为数组:扩展运算符 …

//数组去重
var arr=[1,2,2,3,5,4,2,6]
var set=new Set(arr)

//将Set集合转为数组
// 方法一
var newArr=[...set]
console.log(newArr)// [1, 2, 3, 5, 4, 6]
// 方法二
console.log(Array.from(set))// [1, 2, 3, 5, 4, 6]

8 Map

在ES5中,对象的属性只能字符串

ES6中的map数据类型包含一组有序的键值对,其中键和值可以为任意的数据类型

8.1 创建Map

1、Map对象的创建同样使用Map构造函数

2、Map的存储键值对使用set(key,value)

3、通过get(key),来获取指定的key对应的value

var map=new Map();
console.log(map)//Map(0)

set(key,val)添加指定的键值对

//set()添加属性和属性值
map.set(5,50)
map.set(true,'满分')
console.log(map)//Map(2) {5 => 50, true => "满分"}

get(key)获取指定key对应的value值

//get()获取指定属性的值
console.log(map.get(true))//满分

// 若key不存在则返回undefined
console.log(map.get(liyue));//undefined

8.2 Map和Set类似的三个方法

has(key) 判断给定key是否在map中存在
delete(key) 删除map中指定的key及其对应的值
clear() 移除map中所有的键值对
size map对象的长度

8.3 初始化Map(了解)

map可以像Set一样传入一个数组,但是传入的数组必须为两两是一个子数组(二维数组)

var initMap = new Map([
    ['name','甘雨'],
    ['age','18'],
    [4,false]
])
console.log(initMap)//Map(3) {"name" => "甘雨", "age" => "18", 4 => false}
console.log(initMap.size)//3

8.4 Map遍历

var mapper=new Map();
    mapper.set(1,'胡桃')
    mapper.set(2,'甘雨')
    mapper.set(3,'七七')
    mapper.forEach((val,key)=>{
  	console.log(`key:${key},val:${val}`)
})

for(var key of mapper){
    console.log(key)
}

ES6重要知识点总结

9 Promise

9.1入门问题

1 什么是promise?

promise是异步编程的一种解决方案,传统的解决方案为:回调函数和事件,promise比传统的解决方案更合理。promise是由社区提出的。

  • 简单来说,promise就是一个容器,里面装的有某个未来才会结束的事件,一般为异步事件。
  • promise是一个对象,可以从对象中获取异步操作的消息,promise提供了同意的API,各种异步操作都可以采用同样的方法进行处理。

异步同步?

同步:代码从上到下执行,必须等前面的代码执行完了才执行后面的代码。JS中大部分代码都是同步的。

异步:代码执行到异步代码片时,异步代码片后面的代码可以和异步代码片同时执行。

JS常见的异步:

  • 定时器 setTimeout,setInterval
  • Ajax的异步请求
  • jQuery中的animate()动画
  • ES6中的Promise

2 promise三状态有哪些?

进行中(Pending),已完成(Resolved),已失败(Rejected)

3 promise优点?

  • 有了promise对象,可以把异步操作以同步操作的流程表现出来,避免层层嵌套的回调函数。
  • promise提供了统一的API,使得异步操作更加容易。

4 promise缺点?

  • 无法取消,一旦建立则立即执行,无法中途取消。
  • 如果不设置回调函数,promise内部抛出错误,不会反应到外部。
  • pending(进行中)状态下时,无法得知目前进行到那个阶段了。

5 promise有哪些特点?

  • 对象的状态不受外界的影响,promise代表一个异步操作。
  • 有三种状态:Pending(进行中)、Resolved(已完成)和Rejected(已失败)。
  • 只有异步的结果可以决定当前是哪一种状态,任何操作都不能改变结果。
  • 一旦状态改变,就不会再变。任何时候你都可以得到该结果。
  • Promise的状态只有两种可能:pending->resolved或者pending->rejected。只要这两两种情况发生了状态改变,该结果则凝固,不会再改变,一直保留该结果。

9.2 promise 的基本用法

1 语法

ES6规定Promise对象是一个构造函数,用于生成Promise实例

promise的基本使用语法:

const promise = new Promise(function(resolve,reject){
    ...(some code)
    //判断异步操作是否成功
    if(/*异步操作成功*/){
        resolve(value)
    }else{
        reject(error)
    }
})
说明:promise接受一个函数作为参数,该函数两个参数分别为resolve和reject
他们两个函数(resolve和reject)由js引擎提供,不需要自己部署
'resolve'函数的作用:将Promise状态从'未完成'变成'完成',在异步操作时调用
并将异步调用的结果作为参数传递出去
'reject'函数的作用:将Promise状态从'未完成'变成'失败',在异步操作时调用
并将失败的错误信息作为参数传递出去

promise.then(function(value){
    //成功时函数
},function(error){
    //失败时函数
})

说明:'then'方法可以接收两个回调函数作为参数
第一个回调函数是Promise对象变成resolved状态时调用
第二个回调函数是Promise对象编程rejected状态时调用
其中第二个回调的参数是可选值,不一定会提供

Promise.prototype.catch()接收promise抛出的错误

promise.catch(function(error){
    console.log(error)
})

2 随机数案例

const promise=new Promise(function(resolve,reject){
    //执行相关的异步操作
    let num=Math.random()*2;

    // var str=num>1 ? '调用成功': '调用失败';
    let flag=num>1 ? true: false;
    if(flag){
        // resolve('随机数大于1')
        setTimeout(resolve, 1000,'随机数大于1');
    }else{
        // reject('随机数小于1')
        setTimeout(reject, 1000,'随机数小于1');
    }
})
promise.then(
    function(data){
        //当resolve方法被调用时执行
        console.log(data)
    },
    function(err){
        //当reject方法被调用时执行
        console.error(err)
    })

3 在线视频加载案例

<div class="wrap"></div>
//异步请求视频

let url='https://f.video.weibocdn.com/002akCN7gx07PPZAb9cX01041201dcf50E010.mp4?label=mp4_1080p&template=1920x1080.25.0&trans_finger=d88af6227b88881484d2b59dfbafa136&media_id=4681647124316211&tp=8x8A3El:YTkl0eM8&us=0&ori=1&bf=3&ot=h&ps=3lckmu&uid=34tsO1&ab=3915-g1,5178-g1,3663-g0,5786-g0,966-g1,1493-g0,1192-g0,1191-g0,3601-g17,1258-g0&Expires=1631935806&ssig=fFWuNnPpa5&KID=unistore,video'

const promise=new Promise((resolve,reject)=>{
    let video=document.createElement('video');
    video.src=url
    video.controls='controls'

    //onloadedmetadata当视频加载元数据成功后执行
    video.onloadedmetadata=function(){
        resolve(video)
    }
    video.onerror=function(){
        reject('视频加载失败')
    }
})
promise.then((data)=>{
    console.log(data)
    let wrap=document.querySelector('.wrap');
    wrap.appendChild(data)
},(err)=>{
    console.error(err);
})
//将上面代码封装
function loadVideoSync(url){

    return new Promise((resolve,reject)=>{
        let video=document.createElement('video');
        video.src=url
        video.controls='controls'

        //onloadedmetadata当时拍加载元数据成功后执行
        video.onloadedmetadata=function(){
            resolve(video)
        }
        video.onerror=function(){
            reject('视频加载失败')
        }
    })

}

let promise=loadVideoSync(url)

promise.then((data)=>{
    console.log(data)
    let wrap=document.querySelector('.wrap');
    wrap.appendChild(data)
},(err)=>{
    console.error(err);
})

结果:

成功:

ES6重要知识点总结

失败:

ES6重要知识点总结

4 请求本地json案例

function AjaxSync(url){
    return new Promise((resovle,reject)=>{
        //1.创建ajax对象
        let ajax=new XMLHttpRequest()

        //3.监听状态改变
        ajax.onreadystatechange=function(){
            if(ajax.readyState==4 && ajax.status==200){
                //4.成功则调用resolve
                // console.log(ajax.responseText)
                resovle(ajax.responseText)
            }
        }

        //2.发起get请求
        ajax.open('get',url,true)
        ajax.send(null)
    })
}

const promise =AjaxSync('wearth.json')

promise.then((data)=>{
    var  data =JSON.parse(data)
    console.log(data)
},(error)=>{
    console.error(error)
})

wearth.json数据:

{"desc":"OK","status":1000,"data":{"wendu":"22","ganmao":"风较大,较易发生感冒,注意防护。","forecast":[{"fengxiang":"北风","fengli":"5-6级","high":"高温 24℃","type":"晴","low":"低温 11℃","date":"3日星期六"},{"fengxiang":"北风","fengli":"4-5级","high":"高温 19℃","type":"晴","low":"低温 8℃","date":"4日星期日"},{"fengxiang":"无持续风向","fengli":"微风","high":"高温 21℃","type":"晴","low":"低温 9℃","date":"5日星期一"},{"fengxiang":"无持续风向","fengli":"微风","high":"高温 21℃","type":"多云","low":"低温 10℃","date":"6日星期二"},{"fengxiang":"无持续风向","fengli":"微风","high":"高温 24℃","type":"晴","low":"低温 12℃","date":"7日星期三"},{"fengxiang":"无持续风向","fengli":"微风","high":"高温 23℃","type":"晴","low":"低温 11℃","date":"8日星期四"}]}}

该代码需要在服务器上运行,我使用的WampServer,把代码拷贝到WampServer的www目录下,在浏览器url路径中输入localhost,再进入对应的代码文件。输出结果为:

ES6重要知识点总结

10 async异步

ES2017 标准引入了async函数,使异步操作更加方便

async语法中,可以指定函数返回一个then方法添加的回调函数,当函数执行时,一旦遇到await就先返回等待异步的操作完成之后,再去执行await后面的语句

// async的使用
async function getData(){
    // let promise=new Promise(function(resolve,reject){
    //     setTimeout(resolve,2000,'网路请求成功');
    // })
    return new Promise((resolve,reject)=>{
        setTimeout(resolve,2000,'网路请求成功');
    })
}

async function showAsync(){
    let promise=getData();

    //await等待异步执行的结果后调用
    await promise.then((data)=>{
        console.log(data)
    },(error)=>{
        console.log(error)
    })

    //如果上面不加await,则会直接输出'111',过两秒后才输出'网络请求成功'
    //如果上面加了await,则输出的'111'要等待上面的'网络请求成功'完成后才执行
    console.log(111)
}
showAsync();

async的多种函数使用函数

//标准函数
async funtion foo(){

}

//函数表达式
var foo = async function(){
}

//对象内的方法
let obj = {
    async foo(){}
}

//箭头函数
const foo = async ()=>{}

async的错误处理机制

有时前一个异步操作失败也不要中断后面的异步操作,则可以把await放在try…catch结构。那么不管该异步操作是否成功,第二个await都会执行

主要功能:使用该方法用来防止出错的写法

语法:
try{
    需要执行的代码
}catch(error){
    //error自动获取失败的错误信息
    console.error(error)
}
async function foo(){
    try{
        let value = await new Promise(fun)
        let data = await value.getData();
    }catch(error){
        console.error(error)
    }
}

11 class类

什么是class(类)?

对某一种事物的总称

js其实不是严格意义上的面向对象的语言,因为js中没有类的概念。

在ES5以前生成实例对象主要通过构造函数,(构造函数就是一个普通函数),这种代码风格和传统的面向对象语言差异较大。

ES6提供了一种更接近于传统语言的写法,引入Class这个概念,作为模板定义构造函数。ES6中class只能被认为是一个语法糖,他的绝大部分功能,ES5都可以完成。只是class让对象原型模式更加清晰,更加面向对象。

11.1 基本使用

//ES5中定义一个构造函数
function Animal(name,color){
    this.name=name;
    this.color=color;
    this.say=()=>{
        console.log('喵~')
    }
}

let dog=new Animal('小米','白色')
console.log(dog)//Animal {name: "小米", color: "白色", say: ƒ}

//ES6中定义一个类
class  Person{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
    say(){
        console.log(`你好我是${this.name},我今年${this.age}岁了!`)
    }

    //注意这里面有简写比如:
    // constructor:function(){}直接省略了':function'
    // say:function(){}直接省略了':function'
}
let ming=new Person('小名',16)
ming.say()//你好我是小名,我今年16岁了!

11.2 class中的私有化

私有化方法:只能在内部访问

公有方法:在外部可以正常访问

常见的几种方式:

方式一:在方法名前加_

注意这种方法只是行业规则,程序员自己标记这个方法为私有方法,希望其他人使用的时候不要调用。但是我们还是可以在外部访问到

//ES6
class  Person{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
    say(){
        console.log(`你好我是${this.name},我今年${this.age}岁了!`)
    }
    //定义私有方法
    //方法一,方法名前添加_
    _goHome(){
        console.log(`${this.name}准备回家!`)
    }
}

方法二:将私有方法移除

//ES6
class  Person{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
    say(){
        console.log(`你好我是${this.name},我今年${this.age}岁了!`)
        //方法二:将私有方法移除,在say()方法中调用
        //通过apply,call,bind切换为当前实例化对象
        goHome.call(this)
    }
}
//方法二:将私有方法移除
function  goHome(){
    console.log(`${this.name}准备回家!`)
}

let ming=new Person('小名',16)
ming.say()//你好我是小名,我今年16岁了!
          //小名准备回家!

方式三:使用Symbol(推荐)

//ES6
let gooHome=Symbol()
class  Person{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
    say(){
        console.log(`你好我是${this.name},我今年${this.age}岁了!`)
        this[gooHome]()//?
    }
    [gooHome](){
        console.log('内部方法')
    }
}
let ming=new Person('小名',16)
//调用symbol()创建的私有方法
ming[gooHome]()//内部方法

11.3 class中this指向(了解)

class方法内部如果含有this,默认指向类的实例(new实例化出来的对象),一旦单独使用该方法,则可能报错

class Demo{
    constructor(name){
        this.name = name;
    }
    print(){
        console.log(this.name)
    }
}

var demo = new Demo('胡桃');
demo.print()//

// 结构赋值
let {print} = demo
// console.log(print)
// print()//报错

print中的this默认指向demo实例,如果将其单独使用,则this指代当前的运行环境

解决方案:箭头函数

class Demo{
    constructor(name){
        this.name = name;
        this.print = ()=>{
            console.log(this.name)
        }
    }
}

var demo = new Demo('胡桃');
console.log(demo)
demo.print()

// 结构赋值
let {print} = demo
print()

11.4 class中的继承(重点)

class的继承主要通过’extends’关键字继承

class Animal{}
class Dog extends Animal{}

继承父类Person的所有属性

class Person{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
    say(){
        console.log(`我的名字是${this.name},我今年${this.age}岁了!`)
    }
}
//继承父类Person的所有属性
class stu extends Person{

}

var ming=new stu('小明',16)
ming.say()//我的名字是小明,我今年16岁了!

继承父类Person的所有属性,并且还加新的属性

class Person{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
    say(){
        console.log(`我的名字是${this.name},我今年${this.age}岁了!`)
    }
}

class stu extends Person{
     // 若子类不需要添加新的属性,则不需要写构造函数
    constructor(name,age,score){
        super(name,age);
        this.score=score;
    }
    
    sayScore(){
        console.log(`${this.name}的成绩为${this.score}分`)
    }
    
    toSay(){
        //调用父类的方法使用super和this
        super.say()
    }
}

var ming=new stu('小明',16,98)
ming.toSay()//我的名字是小明,我今年16岁了!
ming.sayScore()//小明的成绩为98分

12 导入导出

export导出文件
import引入文件
上一篇:面试题库自身总结


下一篇:Qml之Json序列化与反序列化