ES6常用

1. Let和const命令

let命令

let命令的特性

  • 不存在变量提升
  • 块级作用域(只在该代码块内生效)
  • 暂时性死区/先声明后调用(在代码块内,使用let声明变量之前,该变量都是不可用的。)
  • 相同作用域下,不允许重复声明

let命令与var命令,都是用来声明变量的。与var相比,let不存在变量提升问题,仅在所在的代码块内有效。

for (var i = 0; i < 5; i++) {
}
console.log('===: ', i) // 5个5
  • 原因:由var声明的变量,在全局作用域内都有效(只要不在其他的两个作用域内),所以在全局只有一个i,每次循环都会i进行修改。并且由var声明的变量,只会循环一次。
  • 解决:使用let来声明变量,let生命的变量仅在当前的块级作用域内有效,每次循环的变量都是一个新的变量。
  • V8引擎会记住上一轮循环的值
let a = 1;
console.log(a) // 1
console.log(this.a) // undefined

ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。

if (true) let x = 1;  // 第一种写法,报错

if (true) {  // 第二种写法,不报错
  let x = 1;
}

暂时性死区

  • 在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”
  • 在代码块内,使用let、const命令,就绑定了该代码块
const命令

const命令特性

  • 常用来声明一个常量,一旦声明,常量的值便不能修改。
  • 基本数据类型的值不能修改。引用数据类型的地址不能修改,但内部的数据可以修改。
  • 只声明不赋值,会报错
  • 其他特性与let特性一致

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

声明变量的六种方法

  • var
  • let
  • const
  • function
  • import
  • class

var命令和function命令声明的全局变量,依旧是顶层对象(window)的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。

顶层对象

  • 在浏览器环境中指的是window对象。node指的是global对象。
  • ES5 之中,顶层对象的属性与全局变量是等价的。var.a = this.a = window.a
  • ES6中全局变量与顶层对象开始脱钩。
  var a = 1;
  console.log(window.a) // 1

  let a = 1;
  console.log(window.a) // undefined

2. 解构赋值

  • 可解构:数组、对象、函数参数、String、Set、Map
  • 只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值
  • 除对象之外,解构其他数据类型。都使用 []
  • 对象解构时,左右两侧数据类型要一致,解构对象键名要相同
  • 可配合扩展运算符、reset参数,一起使用
  • 可以设置默认值,前提是值===undefined时才会生效
  • 如果解构不成功,变量的值就等于undefined

作用

  • 交换变量的值
  • 提取数据
  • 函数参数的默认值
// array
let arr = [1,2,3,4];
let [r1, r2 ,...r3] = arr;

// object
let obj = {
  name: '啦啦啦',
  age: 25,
  type: true
};
let {name, ...age} = obj;

// String
let str = 'string';
let [s1, ...s2] = str;

// Set
let [a1, a2, a3, a4] = new Set(arr);

// Map
let [b1 ,b2] = new Map().set({name: 'map1'}, true).set({name: 'map2'}, false)

// 解构函数参数
function f ([a, b]) {
  console.log(a, b)
}
f([1,2])

// 默认值
let [x, y, ...z] = ['a']
console.log(z) // []

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

3. 扩展运算符 & reset参数

  • 可扩展数组、字符串、Set
  • 主要用于函数调用,扩展参数
  • rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错
function arrs (a, b, c) {
    console.log(a, b, c)
}
let a = [1,2,3];
arrs(...a)

扩展运算符的应用

  • 复制数组: let a3 = […a1];
  • 合并数组: […a1,…a2]
  • 与解构赋值结合
  • 将字符串转为真正的数组: […str]
  • 实现了 Iterator 接口的对象
  • Map 和 Set 结构,Generator 函数

4. 箭头函数

  let a = () => '10'
  • ES6允许使用 => 定义函数
  • 没有或有多个参数时使用()来表示
  • 不加{},默认为return
  • 作用:1.优化回调函数 2.更加简洁,减少代码量
function f () {
  setTimeout(() => {
    console.log('id: ', this.id)
  }, 100)
}

let id = 21;
f.call({id: 42})
  • 箭头函数本身没有this。它的this是定义时所在的对象,而不是调用时的对象 || 本身没有this,内部this就是外部(普通函数)的this

  • 因为没有this,所以不能使用call,apply,bind方法,但外层的普通函数可以使用

  • 因为没有this,所以不能当做构函函数,不能与new一起使用

  • 没有arguments参数,可使用reset参数代替

  • 将动态this变为静态this

补充

  • 参考文章
  • 箭头函数没有prototype(原型),箭头函数本身没有this
  • 箭头函数的this在定义的时候继承自外层第一个普通函数的this。
  • 如果箭头函数外层没有普通函数,严格模式和非严格模式下它的this都会指向window(全局对象)

箭头函数转换为ES5

// ES6
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log('id:', _this.id);
  }, 100);
}

5. Promise()

  • 含义: Promise是解决异步编程的一种解决方案
  • 作用:解决异步回调问题,回调地狱
  • 三种状态:进行中,成功,失败
  • 特点:1.Promise的状态不受外部影响 2.状态一旦改变,便不会再变
  • 缺点
    • 无法取消Promise,一旦新建它就会立即执行,无法中途取消
    • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
    • 当处于pending状态时,无法得知目前进展到哪一个阶段
基本用法
let pro = new Promise((resolve, reject) => {
  resolve(100)
})
  • Promise对象是一个构造函数,用来生成Promise实例
  • 接受一个回调函数,回调函数有两个参数:resolve,reject
  • Promise一旦新建便会立即执行
then()
let pro = new Promise((resolve, reject) => {
  resolve(100)
})

pro.then(res => {
  console.log('成功:', res)
  return Number(res) * 2
}).then(res => {
  console.log('链式调用:', res)
}).catch(err => {
  console.log('失败:', err)
})
  • then()
    • then方法,是Promise实例状态改变时的回调函数
    • 返回一个新的Promise对象,此时才是异步,catch同理 || then方法是异步执行的,之前都是同步执行
    • 可以链式调用
  • catch(): 发生错误时的回调函数

补充

promise.then(function(value) {
  // success
}, function(error) {
  // failure
})
  • then方法可以接受两个回调函数作为参数
    • 第一个回调函数是Promise对象的状态变为resolved时调用
    • 第二个回调函数是Promise对象的状态变为rejected时调用,第二个函数是可选的,不一定要提供
Promise().all()方法
  • 参考文章
  • Promise.all方法用于将多个 Promise 对象实例包装,生成并返回一个新的Promise实例
  • Promise.all方法接受一个数组作为参数(Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例)
Promise.all([  // 数组中所有的promise实例都变为resolve的时候,该方法才会返回
  getVirtualCoinAnalyze(),
  getEarningsCount()
]).then(res => {  // res中包含所有数据
  let [ dianying, youying ] = res;  // 配合解构赋值进行使用
  this.data = dianying.data;
}).catch(err => {  //  当数组中有一个promise对象,状态为reject时,整个Promise.all调用会立即终止,并返回一个reject的新的promise对象
  console.log(err)
})
Promise().resolve()
// 返回一个新的Promise实例,状态为resolve
let resolve = Promise.resolve('成功');

resolve.then(res => {
  console.log(res)
})
Promise().reject()
// 返回一个新的Promise实例,状态为reject
let reject = Promise.reject('失败');

reject.catch(err => {
  console.log(err)
})

6. Iterator && for…of

Iterator(迭代器)
  • 含义:为不同的数据结构,提供统一的访问机制。任何数据只要部署了Iterator接口,就可以进行遍历操作
  • 作用
    • 为不同的数据提供统一的访问机制
    • 使数据结构成员按某种次序排列
    • 创造新的遍历命令 for…of

ES6规定 默认的Iterator接口 部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”

原生具备Iterator接口的数据结构

  • Array
  • String
  • Set
  • Map
  • Arguments

调用Iterator的场合

  • 解构赋值
  • 以数组为参数的方法
    • for…of
    • set
    • map
    • Array.from
    • Promise.all()
for…of
  • ES6引入for…of,可以遍历所有的数据结构
  • for…of循环内部调用的是数据结构内部的symbol.iterator方法
  • 可遍历
    • 数组
    • 字符串
    • set
    • map
    • arguments对象
    • 带有symbol.iterator的对象

for...in && for..of

  • for…in

    • 主要是用来遍历对象,不适合遍历数组
    • 循环读取的是键名
  • for…of

    • 可遍历所有数据结构
    • 循环读取的是键值
let obj = {
  0: '小明',
  1: 22,
  length: 2
}

let newObj = Array.from(obj)
for (let i of newObj) {
  console.log('===: ', i)
}

7. Set 和 Map 数据结构

数据结构

  • Array
  • Object
  • Set
  • Map
Set()
  • ES6新增的数据结构,类似于数组,内部的值都是唯一的,不存在重复的数据,常用于数组去重
  • 是一个构造函数
// 一维数组去重
let arr = [1,2,1,2,3,4];
console.log('转换数组的方式1', [...new Set(arr)])
console.log(Array.from('转换数组的方式2', new Set(arr)))

// 字符串去重
console.log([...new Set('aassdd')].join('-'))

set()的操作方法

  • size: 返回Set实例的成员总数
  • add
  • has: 返回一个布尔值,表示该值是否为Set的成员
  • delete
  • clear
let newSet = new Set();

newSet.add(1)
console.log(newSet.size)

newSet.add(2)
newSet.delete(2)
console.log(newSet.has(2))

newSet.clear()
WeakSet()
  • 含义:与Set类似,也是不重复值得集合
  • 区别
    • WeakSet的值只能是对象,而不能是其他类型的值
    • WeakSet中的对象都是弱引用,垃圾回收机制会自动回收该对象所占用的内存(不会考虑是否还在占用)
    • WeakSet 的成员是不适合引用的,因为它会随时消失
  • 场景:WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失
let newSet = new WeakSet();
// let arr = [[1,2],[3,4]]
let arr = [
  {name: '小明'},
  {name: '小红'}
]
newSet.add(arr)
console.log(newSet)
  • 是一个构造函数
  • 接受一个数组或类似数组的对象作为参数(实际上,任何具有 Iterable 接口的对象,都可以作为 WeakSet 的参数)
  • 不能遍历
  • 操作方法
    • add()
    • delete()
    • has()
Map()
  • Object

    • 键值对,键名只能是字符串
    • 字符串 - 值
  • Map()

    • ES6新增数据结构,类似于对象
    • 键名可以是任意类型,即值 —— 值
    • 是一个构造函数,接受数组作为参数
    • Map的键名实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键
let arr = [
  ['name', '小明'],
  ['age', '22']
]
let newMap = new Map(arr);
console.log(newMap.get('name'))
  • 操作方法
    • size()
    • set()
    • get()
    • has()
    • delete()
    • clear()
let newMap = new Map();
let a = {name: '小明'};
newMap.set(a, '这是一个值')

console.log(newMap.get(a))
WeakMap()
  • WeakMap只接受对象作为键名,null除外
  • WeakMao的键名所指向的对象,不计入垃圾回收机制
  • 是一个构造函数
  • 不可遍历
  • 场景:以DOM节点作为键名
  • 操作
    • set()
    • get()
    • has()
    • delete()

8. 模块化

  • 称为“编译时加载”或者静态加载
  • ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict"
  • 作用:按需加载
export命令
  • export命令用于规定模块的对外接口
  • exprot可以输出变量,方法,class, 可以使用 as 进行重命名
  • export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系
  • export命令可以出现在模块的任何位置只要处于模块顶层就可以。如果处于块级作用域内,就会报错,因为处于条件代码块之中,就没法做静态优化了

export的三种写法

// 第一种写法
export var num = 100; 

// 推荐使用第二种写法,这样写更加直观
var num = 100;  
export function totail (x, y){
  return x * y
}
export {
  num,
  totail
}

// 第三种写法
var num = 100; 
export {
  num as isNum // 使用 as 关键字重命名。之后便可以使用不同的名字输出两次
}
import命令
  import { foo } from './pro.js'
  import { num as isNum } from './profile'
  • 接受一对{ },里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块对外接口的名称相同
  • from指定模块文件的位置可以是相对路径,也可以是绝对路径,.js后缀可以省略
  • import命令具有提升效果,会提升到整个模块的头部,首先执行, 静态执行,不允许有表达式
  • import命令要使用as关键字,将输入的变量重命名
import {a} from './xxx.js'
a.foo = 'hello'; // 合法操作
  • import命令输入的变量都是只读的,因为它的本质是输入接口。只能调用,不能对加载的功能做其他修改、如果是对象的话,可以修改
exprot default 命令
  import fo from './pro'
  • export default命令用于指定模块的默认输出
  • 一个模块只能有一个默认输出,因此export default命令只能使用一次
  • import命令后面才不用加大括号
  • 本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字
  exprot defalut function foo() {
    console.log('第一种写法')
  }
  
  function foo () {
    console.log('第二种写法')
  }
  function fun () {
    console.log('默认导出')
  }
  exprot default { // 只能有一个 export default,但可以导出多个方法
    foo,
    fun
  }

exprot defalut可以和 exprot 一起配合使用

import 默认接口,{foo} from './foo'

exprot default function sum () {
  console.log('默认接口')
}

function foo () {
  console.log('普通对外接口')
}

exprot {
  foo
}
模块的整体加载
import * as aclice from './aclice'
console.log('圆面积:' + circle.area(4));
  • * 代表加载所有aclice模块中的输出的内容, 配合as使用

公用方法实现异步回调

  • 目的:解决异步回调问题
  • 创建一个公用方法并导出
// 公用方法
function checkMsg (text, success) {
  workworldAPI.checkMsg(text).then(res => {
     success(true)  // sussess是回调函数
  }).catch(err => {
    console.log(err.message)
  })
}

export default {
  checkMsg
}
// 调用该方法
import checkMsg from '@/utils/processAmount'

checkMsg('参数', (res) => { // 回调函数
    console.log(res) // true
})
function aaa (num, success, err) {
  if (num > 5) {
    success('成功的回调')
  } else {
    err('失败的回调')
  }
}

aaa(8, res => {
  console.log('res: ', res)
}, err => {
  console.log('err: ', err)
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值