ES6语法笔记

1、let变量声明以及声明特性

  1. 变量不能重复声明

  2. 块级作用域 (let)

    作用域:全局、函数、eval(严格模式下)、块级作用域

    块级作用域:if、else、while、for

{
    let a = 1
}
console.log(a) // ReferenceError is not defined
  1. 不存在变量提升
console.log(a) // ReferenceError Cannot not access 'a' before initialization
let a = 1
  1. 不影响作用域链
// fn运行,但是函数作用域中没有,所以向上一级查找,找到a再输出
{
    let a =1
    function fn(){
        console.log(a)
    }
    fn()
}

案例


2、const声明常量以及特点

  1. 一定要赋初始值
const A // SyntaxError Missing initializer in const declaration
  1. 一般常量使用大写
  2. 常量值不能修改
TypeError Assigment to constant variable
  1. 块级作用域
  2. 对于数组和对象的元素修改,不算对常量的修改,不会报错
const ALPHBAT = ['A','B']
ALPHBAT.push('C') // 不会报错,常量指向的地址没有改变

3、变量解构赋值

允许按照一定模式从数组和对象中提取值,对变量进行赋值

  1. 数组的解构
const FRUITS = ['苹果','香蕉','草莓']
let [apple,banana,strawberry] = FRUITS
console.log(apple) // 苹果
console.log(banana) // 香蕉
  1. 对象的解构
const student = {
    name:'xiaoming',
    age:0,
    gender:0,
    play:function(){
        console.log('快乐小学生')
    }
}
let {name, age,gender,play} = student

console.log(name) // xiaoming
play() // 快乐小学生

4、模板字符串 ``

  1. 内容中可以直接出现换行符
let str = `<div>
			<p>模板字符串</p>
		</div>`
  1. 变量拼接
let age = 18
let str = `xiaoming今年${age}岁`
console.log(str) // xiaoming今年18岁

5、对象简化

允许在大括号内,直接写入变量和函数,作为对象的属性和方法

let name = 'xiaoming'
let play = function(){
    console.log('快乐小学生')
}
const student = {
    name,
    play,
    improve(){
        cosole.log('函数声明简化')
    }
}

6、箭头函数以及声明特点

  1. 声明函数
let fn = function(){}
let fn = (a,b) => {
    return a + b
}

  1. this是静态的,this始终指向函数声明时所在作用域的this的值
function getName(){
    console.log(this.name)
}

let getName2 = () => {
    console.log(this.name)
}

window.name = 'window'

const student = {
    name:'xiaoming'
}
// 直接调用
getName() // window
getName2() // window

// call方法调用
getName.call(student) // xiaoming
getName2.call(student) // window
  1. 不能作为构造实例化对象
let Person = (name, age)=>{
    this.name = name,
    this.age = age
}
let me = new Person('xiaoming',18)
console.log(me) // TypeError Person is not a constructor
  1. 不能使用arguments变量

    arguments保存实参

let fn = ()=>{
    console.log(arguments) // ReferenceError arguments is not defined
}
fn(1,2,3) 
  1. 箭头函数的简写
  • 省略小括号,当形参有且只有一个
let add = n =>{
    return n+n
}
console.log(add(9))
  • 省略花括号,当代码体只有一条语句,此时语句中的return也必须省略。语句的执行结果就是函数的返回值
let pow = (n) => n*n

console.log(pow(9))

案例

适合与this无关的回调,定时器,数组的方法对象回调

不适合与this有关的回调,事件回调,对象的方法

7、函数参数默认值的设置

  1. 形参的初始值,具有默认值的参数,一般位置要靠后
function add(a,b,c=10){
    return a + b + c
}
let result = add(1,2)
console.log(result) // 13

// 默认值参数放中间没有意义
function add(a,c=10,b){
    return a + b + c
}
let result = add(1,2)
console.log(result) // NaN undefined + number
  1. 与解构赋值结合
function connect({host,username,password,port}){
    console.log(host) // localhost
    console.log(username) // root
}
connect({
    host:'localhost',
    username:'root',
    password:'root',
    port:"3306"
})

// 给属性赋初始值,如果调用时host属性没有传,就使用默认值
function connect({host='127.0.0.1',username,password,port}){
    console.log(host) // 127.0.0.1
    console.log(username) // root
}
connect({
    username:'root',
    password:'root',
    port:"3306"
})

8、rest参数

引入rest参数,用于获取函数的实参,用来代替arguments

  1. 获取参数,rest参数必须放到参数最后
// ES5
function fruit(){
    console.log(arguments) // 对象
}
fruit('apple','banana','strawberry')

// ES6
function fruit(...args){
    console.log(args) // 数组,可以使用数组方法
}
fruit('apple','banana','strawberry')

// rest参数必须放到参数最后
function fn(a,b,...args){
    console.log(a) // 1
    console.log(b) // 2
    console.log(args) // [3,4,5,6]
}
fn(1,2,3,4,5,6)

function fn(a,...args,b){
    console.log(a) // SynataError Rest parameter must be last formal parameter
}
fn(1,2,3,4,5,6)

9、扩展运算符

数组转换为逗号分隔的参数序列

const fruits = ['apple','banana','strawberry']

function fruit(){
    console.log(arguments)
}
fruit(fruits) // arguments对象,参数只有一个,fruits在数组中
fruit(...fruits) // arguments对象,参数有三个,相当于fruit('apple','banana','strawberry')

应用

  1. 数组合并
const fruits = ['apple','banana','strawberry']
const animals = ['cat','dog']

const fa = fruits.concat(animals)
console.log(fa) // ['apple','banana','strawberry','cat','dog']

const fa = [...fruits,...animals]
console.log(fa) // ['apple','banana','strawberry','cat','dog']
  1. 数组克隆(浅拷贝)
const fruits = ['apple','banana','strawberry']
const Fruits = [...fruits]
consoloe.log(Fruits) // ['apple','banana','strawberry']
  1. 将伪数组转为真正的数组
const divs = documents.querySelectorAll('div')
console.log(divs) // __proto__:Object

const divArr = [...divs]
console.log(divArr) // []

10、Symbol介绍与创建

引入原始数据类型,表示独一无二的值。JavaScript第七种数据类型。

  • 特点
    1. Symbol的值是唯一的,用来解决命名冲突的问题
    2. Symbol的值不能与其他数据进行运算
    3. Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
  1. 创建Symbol,值是唯一的
let s = Symbol()
console.log(s, typeof s) // Symbol() "symbol"

let s2 = Symbol('fruits')
let s3 = Symbol('fruits')
console.log(s2 === s3) // false

let s4 = Symbol.for('fruits')
let s5 = Symbol.for('fruits')
console.log(s4 === s5) // true
  1. 不能与其他数据进行运算
let result = s + 100 // TypeError cannot convert a Symbol value to a number
U S O N B
undefined string object null boolean
symbol number
  1. 给对象添加属性和方法
// game内容未知
let game = {
    name:'xiaoming',
    up(){},
    down(){}
}

// 安全的向game对象中添加方法
let methods = {
    up:Symbol(),
    down:Symbol()
}
game[methods.up] = funtion(){
    console.log('up')
}
game[methods.down] = funtion(){
    console.log('down')
}

console.log(game) // game原有的属性和方法 + Symbol() + Symbol()
let game = {
    name:'狼人杀',
    [Symbol('say')]:function(){
        console.log('发言')
    }
}
console.log(game) // Symbol(say)
  1. Symbol内置值

【Symbol内置值】作为Symbol的属性,【Symbol.Symbol内置值】作为对象的属性

// hasInstance 自己控制类型检测
class Person{
    static [Symbol.hasInstance](param){
        console.log(param)
        console.log('检测类型')
        // return true 则输出为true
    }
}
let o = {}
console.log(o instanceof Person) // {} 检测类型 false
// isConcatSpreadable 控制concat是否可以展开
const arr = [1,2,3]
const arr2 = [4,5,6]
console.log(arr.concat(arr2)) // [1,2,3,4,5,6]

arr2[Symbol.isConcatSpreadable] = false
console.log(arr.concat(arr2)) // [1,2,3,[4,5,6]]

11、迭代器

是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口(对象中的一个属性Symbol.interator),就可以完成遍历操作。

  1. ES6创造了一种新的遍历命令for...of循环,Iterator接口主要提供for...of循环

  2. 原生具备Iterator接口的数据

    Array、Arguments、Set、Map、String、TypedArray、NodeList

// 数组
const fruits = ['apple','banana','strawberry']
// of 键值
for(let v of fruits){
    console.log(v) // apple banana strawberry
}
// in 键名
for(let k in fruits){
    console.log(v) // 0 1 2
}
  1. 工作原理

    1)创建一个指针对象,指向当前数据结构的起始位置

    2)第一次调用对象的next方法,指针自动指向数据结构的第一个成员

    3)接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员

    4)每调用next方法返回一个包含value和done属性的对象

注:需要自定义遍历数据的时候,要想到迭代器

自定义遍历数据

let fruits = {
 name:'水果',
 content:['apple','banana','strawberry'],
 [Symbol.iterator](){
     let index = 0
     let _this = this
     return {
         next:function(){
             if(index < _this.content.length){
                 const result = {value:_this.content[index],done:false}
                 index++
                 return result
             }else{
                 return {value:undefined,done:true}
             }  
         }
     }
 }
}

// 遍历对象
for(let v of fruits){
 console.log(v)
}

12、生成器

生成器函数是ES6提供的一种异步编程解决方案

  1. 声明与调用
function * fn(){
    console.log("hello generator")
}

let generator = fn()
console.log(generator) // 迭代器对象,没有输出函数中的console
generator.next() // hello generator
// yield 函数代码的分隔符,3个yield分为4个块
function * fn(){
    console.log('块1')
    yield '1111'
    console.log('块2')
    yield '2222'
    console.log('块3')
    yield '3333'
    console.log('块4')
}
let generator = fn()
generator.next() // 块1
generator.next() // 块2

for(let v of fn()){
    console.log(v) // 1111 2222 3333 yield后的值
}
  1. 参数传递
function * fn(){
    yield 1111
    yield 2222
    yield 3333
}
let generator = fn()
console.log(generator.next()) //{value:111,done:false}

function * fn(arg){
    console.log(arg) // AAA 
    let one = yield 1111
    console.log(one) // BBB 
    let two = yield 2222
    console.log(two) // CCC
    let three = yield 3333
    console.log(three) // DDD
}
// 整体函数传参
let generator = fn('AAA')
console.log(generator.next()) //返回结果yield后的值  {value:1111,done:false}

// next传入实参,作为上一个`yield`(yield 1111)的返回结果
// 第2次调用,返回yield 1111的结果
console.log(generator.next('BBB')) //{value:2222,done:false}
// 第3次调用,返回yield 2222的结果
console.log(generator.next('CCC')) //{value:3333,done:false}
// 第4次调用,返回yield 3333的结果
console.log(generator.next('DDD')) //{value:undefined,done:true}

实例-异步编程

  1. 需求:1s后输出111,2s后输出222,3s后输出333
function one(){
    setTimeout(()=>{
        console.log(111) // 111
        iterator.next() 
    },1000)
}
function two(){
    setTimeout(()=>{
        console.log(222) // 222
        iterator.next() 
    },2000)
}
function three(){
    setTimeout(()=>{
        console.log(333) // 333
        iterator.next()
    },3000)
}

// 生成器
function * gen(){
    yield one()
    yield two()
    yield three()
}
// 调用
let generator = gen()
generator.next() 
  1. 模拟获取 用户数据—>订单数据—>商品数据,存在先后顺序
function getUsers(){
    setTimeout(()=>{
        let data = '用户数据'
        // 第2次调用next,data将作为第一个yield返回结果
        generator.next(data) // 调用next传参
    },1000)
}
function getOrders(){
    setTimeout(()=>{
        let data = '订单数据'
        generator.next(data)
    },1000)
}
function getGoods(){
    setTimeout(()=>{
        let data = '商品数据'
        generator.next(data)
    },1000)
}

// 生成器
function * gen(){
    let users = yield getUsers()
    console.log(users) // 用户数据
    let orders = yield getOrders()
    console.log(orders) // 订单数据
    let goods = yield getGoods()
    console.log(goods) // 商品数据
}
// 调用
let generator = gen()
generator.next() 

13、Promise

异步编程,语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果,避免回调地狱

通过resolvereject来改变Promise状态,再根据状态调用then方法的不同函数

实现Promise可以看这里✨手写Promise过程记录

  1. 基本使用
// 实例化
const p = new Promise(function(resolve,reject){
    setTimeout(function(){
        let data = '数据库中的用户数据'
        resolve(data)
    },1000)
})

// 调用then方法
p.then(function(value){
    console.log(value) // 数据库中的用户数据
},function(reason){})
// 实例化
const p = new Promise(function(resolve,reject){
    setTimeout(function(){
        let error = '数据库读取失败'
        reject(error)
    },1000)
})

// 调用then方法
p.then(function(value){
    console.log(value) // 数据库中的用户数据
},function(reason){
    console.error(reason) // 数据库读取失败
})
  1. Promise封装读取文件
// 1. 引入fs
const fs = require('fs')
// 2.调用方法读取文件
fs.readFile('./resources/文件.txt',(error,data)=>{
    // 失败,抛出错误
    if(error) throw error
    // 成功,输出内容
    console.log(data.toString()) // 文件内容
})

// 3. 使用Promise封装
const p = new Promise(function(resolve,reject){
    fs.readFile('./resources/文件.txt',(error,data)=>{
        // 失败,抛出错误
        if(error) reject(error)
        // 成功,输出内容
        resolve(data)
})
p.then(function(value){
    console.log(value.toString()) // 文件内容
},function(reason){
    console.log('读取失败')
})
  1. Promise封装Ajax请求
// 1. 创建对象
const xhr = new XMLHttpRequest()
// 2. 初始化
xhr.open('GET','https://api.apiopen.top/getoke')
// 3. 发送
xhr.send()
// 4. 绑定事件,处理响应结果
xhr.onreadystatechange = function(){
    // 判断
    if(xhr.readyState === 4){
        // 判断响应状态码 200-299
        if(xhr.status >= 200 && xhr.status < 300){
            console.log(xhr.response)
        }else{
            console.err(xhr.status)
        }
    }
}
const p = new Promise((resolve,reject)=>{
    const xhr = new XMLHttpRequest()   
    xhr.open('GET','https://api.apiopen.top/getoke')
    xhr.send()

    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
            if(xhr.status >= 200 && xhr.status < 300){
                resolve(xhr.response)
            }else{
                reject(xhr.status)
            }
        }
	}
})

p.then(function(value){
    console.log(value)
},function(reason){
    console.log(reason)
})
  1. Promise.prototype.then方法

返回结果是Promise对象,对象状态由回调函数的执行结果决定。可以链式调用,解决回调地狱。

①回调函数返回非Promise类型(undefined,string....)

​ then的返回Promise对象的状态为成功,返回值为对象的成功的值

②回调函数返回Promise类型

内部Promise的返回状态决定then的返回Promise对象的状态,

const result = p.then(function(value){
    return new Promise((resolve,reject)=>{
        resolve('ok')
    })
})
console.log(result) // resolved ok
const result = p.then(function(value){
    return new Promise((resolve,reject)=>{
        reject('error')
    })
})
console.log(result) // rejectd error

③抛出错误,状态为rejected,值为抛出的错误值

  1. 多文件内容读取
const fs = require('fs')

fs.readFile('./resources/文件1.txt',(error,data1)=>{
    fs.readFile('./resources/文件2.txt',(error,data2)=>{
        fs.readFile('./resources/文件3.txt',(error,data3)=>{
            let result = data1 + data2 + data3
            console.log(result) // 3个文件的内容
        })
    })
})

//使用Promise封装
const p = new Promise(function(resolve,reject){
    fs.readFile('./resources/文件1.txt',(error,data)=>{
        resolve(data)
	})
}
p.then(value=>{
	return new Promise(function(resolve,reject){
        fs.readFile('./resources/文件2.txt',(error,data)=>{
            resolve([value,data])
        })
	}
}).then(value=>{
	return new Promise(function(resolve,reject){
        fs.readFile('./resources/文件3.txt',(error,data)=>{
            value.push(data)
            resolve(value)
        })
	}
}).then(value=>{
	console.log(value.join('')) // 3个文件的内容
}
  1. catch

14、Set

集合类似于数组,但是成员的值是唯一的。

实现了iterator接口,可以使用扩展运算符for...of进行遍历。

let s = new Set()

let s2 = new Set(['apple','banana','apple'])
console.log(s2) // {'apple','banana'}

// size 元素个数
console.log(s2.size) // 2 
// add 添加元素
s2.add('strawberry')
console.log(s2) // {'apple','banana','strawberry'}
// delete 删除元素
s2.delete('apple')
console.log(s2) // {'banana','strawberry'}
// has 检测
s2.has('strawberry')
console.log(s2) // true
// clear 清空
s2.clear()
console.log(s2) // {}

for(let v of s2){
    console.log(s2) // apple banana
}
let arr = [1,2,3,4,5,4,3,2,1]
  1. 数组去重
let result = [...new Set(arr)]
console.log(result) // [1,2,3,4,5]
  1. 交集
let arr2 = [4,5,6,5,6]
let result = [...new Set(arr)].filter(item =>{
    let s2 = new Set(arr2) // 4 5 6
    if(s2.has(item)){
        return true
    }else return false
})

// 化简
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item))

console.log(result) // [4 5]
  1. 并集
let arr2 = [4,5,6,5,6]
let union = [...new Set([...arr,...arr2])]
console.log(union) // [1,2,3,4,5,6]
  1. 差集
let arr2 = [4,5,6,5,6]
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)))
console.log(diff) // [1,2,3]

15、Map

map类似于对象,也是键值对的集合。但是键的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

实现了iterator接口,可以使用扩展运算符for...of进行遍历。

let m = new Map()

// 添加元素
m.set('name','xiaoming')
m.set('change',function(){
    console.log('change')
})
let key ={name:'fruit'}
m.set(key,['apple','banana'])

console.log(m)

// size 元素个数
// delete 删除
// get 获取
console.log(m.get('name')) // xiaoming
// clear 清空

// for...of

16、class类

class Phone{
    // 构造方法 名字不能修改
    constructor(brand,price){
        this.brand = brand
        this.price = price
    }
    // 方法必须使用该语法,不能使用ES5的对象
    call(){
        console.log('可以打电话')
    }
}
let onePlus = new Phone('1+',1999)
console.log(onePlus)
  1. 静态成员
function Phone(){}

Phone.name='手机'
Phone.change = function(){
    console.log('我可以改变世界')
}
let nokia = new Phone()
console.log(nokia.name) // undefined
nokia.change() // TypeError is not a function

Phone.prototype.size = '5.5inch'
console.log(nokia.size) // 5.5inch

Phone.namePhone.change属于函数对象,不属于实例对象。

Phone.namePhone.change称为静态成员

实例对象的属性和构造函数的原型相通

class Phone{
    static name = '手机'
}
let nokia = new Phone()
console.log(nokia.name) // undefined
console.log(Phone.name) // 手机

static 标注的name属于类而不属于实例对象

  1. class的类继承
// ES5构造函数继承
// 手机
function Phone(brand, price){
    this.brand = brand;
    this.price = price;
}
Phone.prototype.call = function(){
    console.log("我可以打电话");
}
// 智能手机
function SmartPhone(brand,price,color,size){
    Phone.call(this, brand,price);
    this.color = color;
    this.size = size;
}
// 设置子级构造函数的原型
SmartPhone.prototype = new Phone;
SmartPhone.prototype.constructor = smartPhone;
// 声明子类的方法
SmartPhone.prototype.photo = function({
    console.log("我可以拍照")
}
SmartPhone. prototype.playGame = function({
    console.log("我可以玩游戏")
}

const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch')
console.log(chuizi)
// ES6
class Phone{
    // 构造方法
    constructor(brand,price){
        this.brand = brand;
        this.price = price;
    }
    // 父类的成员属性
    call({
    	console.log('我可以打电话!!');
    }
}

class SmartPhone extends Phone{
    // 构造方法
    constructor(brand,price,color,size){
    	super(brand,price);// Phone.call(this,brand,price)
        this.color = color;
        this.size = size;
    }
    photo(){
        console.log('拍照');
    }
    playGame(){
        console.log('玩游戏');
    }
}

const xiaomi = new SmartPhone('小米',799,'黑色','4.7inch')
console.log(xiaomi)
  1. 子类对父类方法的重写
  2. getter和setter
// get 和 set
class Phone{
    get price(){
        console.log("价格属性被读取了");
        return 'iloveyou';
    }
    set price(newVal){
    	console.log('价格属性被修改了');
    }
}
// 实例化对象
let s = new Phone();
console.log(s.price);// iloveyou
s.price = 'free';

17、数值扩展

  1. Number.EPSILON是JavaScript表示的最小精度

    EPSILON属性的值接近于 2.2204468492503130808472633361816E-16

function equal(a,b){
 return Math.abs(a-b) < Number.EPSILON
}
console.log(0.1 + 0.2 === 0.3) // false
console.log(equal(0.1 + 0.2, 0.3) // true
  1. 二进制和八进制
  2. Number.isFinite检测一个数值是否为有限数
console.log(Number.isFinite(100)) // true 
console.log(Number.isFinite(100/0) // false
console.log(Number.isFinite(Infinity)) // false
  1. Number.isNaN检测一个数值是否为NaN
console.log(Number.isNaN(123)) // false
  1. Number.parseInt字符串转整数, Number.parseFloat
console.log(Number.parseInt('5211314love')) // 5211314
console.log(Number.parseFloat('3.1415926神奇')) // 3.1415926
  1. Number.isInteger判断一个数是否为整数
console.log(Number.isInteger(5)) // true
console.log(Number.isInteger(2.5)) // false
  1. Math.trunc将数字的小数部分抹掉
console.log(Math.trunc(3.5)) // 3
  1. Math.sign判断一个数到底为正数负数还是零
console.log(Math.sign(100)) // 1
console.log(Math.sign(0)) // 0
console.log(Math.sign(-200)) // -1

18、对象方法扩展

  1. Object.is判断两个值是否完全相等
console.log(Object.is(120,121)) // false
console.log(Object.is(120,120)) // true
console.log(Object.is(NaN,NaN)) // true
console.log(NaN === NaN) // false
  1. Object.assign对象的合并

如果重名,第二个参数会覆盖第一个参数

const config1 = {
    host: 'localhost',
    port:3306,
    name: 'root',
    pass: 'root',
    test:'test'
}
const config2 = {
    host: 'http: //atguigu.com',
    port: 3306,
    name: 'atguigu.com',
    pass: 'iloveyou',
    test2:'test2'
    
}
console.log(Object.assign(config1,config2)) // config2覆盖了config1,test保留,test2不保留
  1. Object.setPrototypeof设置原型对象 Object.getPrototypeof
const school = {
    name:'尚硅谷'
}
const cities = {
    xiaoqu:['北京','上海','深圳']
}
Object.setPrototypeof(school, cities)
console.log(school) // __proto__ cities{}
console.log(Object.getPrototypeof(school)) // cities{}

19、模块化

  1. 好处
  • 防止命名冲突
  • 代码复用
  • 高维护性
  1. 语法

export:规定模块的对外接口

import:输入其他模块提供的功能

<script src="./src/js/app.js" type="module"></script>
  • 导出export
// 分别暴露
export a = 1
export function change(){
    console.log('change')
}
import * as m1 from './js/m1.js'
// 统一暴露
export {a,b}
import * as m2 from './js/m2.js'
// 默认暴露
export default{
    //....
}
import * as m3 from './js/m3.js'
m3.defalut.change()
  • 引入import

通用导入

import * as m1 from './js/m1.js'

解构赋值

import {a,change} from './js/m1.js'
import {a as A} from './js/m2.js'
import {defalut as m3} from './js/m3.js'
// 直接使用

简便形式(针对默认暴露)

import m3 from './js/m3.js'
  1. babel对ES6模块化代码转换
原文地址:https://www.cnblogs.com/wattmelon/p/13895450.html