ES6复习小结

142 阅读9分钟

前言

此篇文章是我二刷es6的一些想法和总结,笔记。仅用于个人以后复习,有的地方不太详细因为感觉自己已经了解了,所以不会详细写,只重点写一些区别和面试题,初学者勿入。

ES6是JavaScript语言的一次重大更新(2015),引入了很多新的语法特性,解决了一些bug

有的语法特性在日常并不会用到,我们也就少记一些,以免增加大脑负担,在这里我只列举es6常用的语法

不常用的:字符串的编码扩展,正则的扩展,数值的扩展,Symbol,Map

let和const

var

  • 存在变量提升
  • 存在函数作用域
  • 可以声明同一个变量(覆盖),可以覆盖掉window上带的属性

let

  • 不存在变量提升
  • 存在块级作用域,let声明的变量只在块级作用域内有效
  • 用于声明变量,不能重复声明变量

const

  • 不存在变量提升
  • 存在块级作用域,const声明的变量只在块级作用域内有效
  • 用于声明常量,声明的常量一般大写,且不能被修改,用const声明引用数据类型时,可以修改内部数据

变量的解构赋值

数组的解构赋值

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

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

对象的解构赋值

对象的key值需要对应

let {a,b} = {a:1,b:2}
console.log(a,b)//1,2

字符串的解构赋值

let [a,b,c] = 'hello'
console.log(a,b,c)//h,e,l

函数参数的解构赋值

function sum([a,b]){
  return a+b
}
sum([1020])//30

字符串的扩展

锦上添花,实用性不高,适当记

模板字符串

let name = '嘟噜小脾气'
let str= `你好${name}`
console.log(str)//你好嘟噜小脾气

字符串的新增方法

includes()

查找字符串内是否包含该参数字符串

  • 以前:indexOf()==> 返回 -1 || 下标
  • 新增:includes()==> 返回布尔值 false || true
let name = '嘟噜小脾气'
let str = `你好${name}`
console.log(str)//你好嘟噜小脾气

console.log(name.indexOf('小'));//2
console.log(name.indexOf('小脾气'));//2
console.log(name.indexOf('小脾Q'));//-1
console.log(name.indexOf('哈哈'));//-1

console.log(name.includes('小'));//true
console.log(name.includes('小脾气'));//true
console.log(name.includes('小脾Q'));//false
console.log(name.includes('哈哈'));//false

startsWith(),endsWith()

  • startsWith():查找该参数字符串是否存在于字符串开头
  • endsWith():查找该参数字符串元素是否存在于字符串结尾

以上2个方法平时可能不太常用,因为以前的方法可能会更好用

startsWith('a')
str[0] == 'a'

endsWith('a')
str[str.length-1] == 'a'

repeat()

重复该字符串多少次

let name = '嘟噜小脾气'
console.log(name.repeat(3));//嘟噜小脾气嘟噜小脾气嘟噜小脾气

padStart(),padEnd()

在字符串前,后填充参数,补充字符串

let name = '嘟噜小脾气'

console.log(name.padStart(10, '0'));//00000嘟噜小脾气
console.log(name.padEnd(10, '0'));//嘟噜小脾气00000

使用场景:

给newDate()出来的时间补0

trimStart(),trimEnd()

  • trim():去除字符串前后的空格
  • trimStart():去除字符串前面的空格
  • trimEnd():去除字符串后面的空格

replaceAll()

替换字符串

let name = '嘟噜小脾气'

console.log(name.replace(/小/g, '大大'));//嘟噜大大脾气
console.log(name.replaceAll('小', '大大'));//嘟噜大大脾气

数值的扩展

es6本身对数值操作的方法例如parseInt(),parseFloat()是挂载在window对象上的,es6认为它的分类并不合理,便把它挂载到了Number对象上,现在还能在window对象使用,也能用Number.parseInt()

函数的扩展

箭头函数

箭头函数和普通函数的区别:

  • 箭头函数不能new
  • 箭头函数内部没有arguments对象
  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

也就是说一般箭头函数的this都指向window

普通函数this,谁调用这个函数,this就代表谁

函数扩展

  • 可以添加函数参数的默认值
  • ...操作符(可以用来拆分和合并数组)

面试题:合并数组的方法有哪些

let arr1 = [1, 2]
let arr2 = [3, 4, 5]

console.log(arr1.concat(arr2));//[1,2,3,4,5]
console.log([...arr1, ...arr2]);

数组的扩展

扩展运算符...

 

可以用来替代apply()方法

Math.max.apply(null,[1,5,3])

Math.max(...[1,5,3])

Array.from()

用于将两类对象转为真正的数组:

  1. 类似数组的对象(array-like object)

eg:用dom操作获取到的DOM节点对象

let lis = document.getElementsByTagName('li')
  1. 可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。
let obj = {
  a: 1,
  1: 2,
  length: 3
}
console.log(Array.from(obj));//[ undefined, 2, undefined ]

Array.of()

用于将一组值,转换为数组。

console.log(Array.of(1, 5, 7, 9, 5, 4));//[ 1, 5, 7, 9, 5, 4 ]

find()和findIndex()

  • find():返回查找到的符合条件的第一个数组元素 || undefined
  • findIndex():返回查找到的符合条件的第一个数组元素下标 || -1

数组的includes()

查到返回true,没查找到返回 false

flat()

扁平化数组,默认只扁平化2层的数组,要扁平化多层数组的话,有多少层就调用几次这个方法,或者给flat()传递参数flat(num)

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

console.log(arr.flat().flat());
console.log(arr.flat(2));//[1,2,3]

对象的扩展

对象内的方法写法改进

let obj = {
  fun:function(){
    return 'fun'
  }
}

let obj = {
  fun(){
    return 'fun'
  }
}

简化对象

let obj = {str:str}
let obj = {str}//key和value一样时可以直接简化

遍历对象方法

keys(),values(),entries()

for in

循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)

let obj = {
  a: 1,
  b: 2,
  c: 3
}
for (let v in obj) {
  console.log(v);//a  b  c
}

for of

适用于遍历数组元素

let obj = {
  a: 1,
  b: 2,
  c: 3
}
for (let k of Object.keys(obj)) {
  console.log(k);//a b c
}
for (let v of Object.values(obj)) {
  console.log(v);//1 2 3
}
for (let [k, v] of Object.entries(obj)) {
  console.log(k, v);//a 1    b 2    c 3
}

对象新增的方法

Object.is()

用来判断是否相等,主要是解决ES5之前的:==,===的问题

console.log(NaN == NaN);//false
console.log(NaN === NaN);//false

console.log(Object.is(NaN, NaN));//true
console.log(Object.is({}, {}));//false
console.log([1, 2, 3] == [1, 2, 3]);//false
console.log(Object.is([1, 2, 3], [1, 2, 3]));//对象永远不可能相等

Object.assign()!!!非常重要

用于对象的合并

let obj1 = {
  a: 1
}
let obj2 = {
  b: 2
}

Object.assign(obj1, obj2)//把obj2合并到obj1里

console.log(obj1, obj2);//{ a: 1, b: 2 } { b: 2 }

合并的对象是用浅拷贝,obj2值的改变会影响到合并完的obj1

let obj1 = {
  a: 1
}
let obj2 = {
  a: 2,
  m: {
    a: "111"
  }
}

obj2.m.a = "222"
Object.assign(obj1, obj2)
console.log(obj1, obj2);
//{ a: 2, m: { a: '222' } } { a: 2, m: { a: '222' } }

使用场景:

配置默认参数对象后合并传过来的参数对象

let objDefault = {
  inputText: '用户名xxx',
  inputPwd: '密码xxx'
}

let obj = {
  inputPwd: '这不是密码',
  inputSum: '这是yyyy'
}

let setting = Object.assign(objDefault, obj)
console.log(setting.inputText);

Class

面向对象的三大特性:

封装

隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性

继承

提高代码复用性,继承是多态的前提

多态

父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高程序的扩展性

class的基本格式

class 类名称{
  constructor(){
    this.属性名 = 值
  }
  方法1(){}
  方法2(){}
}
//es5
function Person1(name) {
  this.name = name
}

Person1.prototype.run = function () {
  return this.name + "run"
}

let person1 = new Person1('张三')
console.log(person1.name);//张三
console.log(person1.run());//张三run
//es6
class Person2 {
  constructor(name) {
    this.name = name
  }
  run() {
    return this.name + 'run'
  }
}

let person2 = new Person2('李四')
console.log(person2.name);//李四
console.log(person2.run());//李四run

类继承

class 子类 extends 父类{
  constructor(){
    super()
    this.属性名 = 值
  }
  方法1(){}
  方法2(){}
}
class Parent {
  constructor() {
    this.money = '父亲的钱'
  }
  fatherFun() {
    return '父亲的方法'
  }
}

class Child extends Parent {
  constructor() {
    super()
    this.age = 18
  }
  childFun() {
    return '这是子类的方法'
  }
}

let children = new Child()
console.log(children.money);
console.log(children.fatherFun());

私有方法和私有属性

私有方法和私有属性,是只能在类的内部访问方法和属性,外部不能访问。这是常见需求,有利于代码的封装,但ES6不提供,只能通过变通方法模拟实现。

私有方法:

    1. 在方法名前加下划线(约定俗称,但实际上还是非私有的)
    1. 使用Symbol

Symbol(基本上不会用)

Symbol是一个独一无二的值,是原始数据类型

let s = Symbol('描述')

console.log(s);//Symbol(描述)
let ss = Symbol.for('描述')//获取这个Symbol

Set和Map(Map基本上不会用)

Set()

 

没有重复的值,可以使用Set去重

let set = new Set([1, 2, 5, 4, 5, 1, 7, 8, 4, 4,])
console.log(set);//Set(6) { 1, 2, 5, 4, 7, 8 }

有几种去重方式:

  • ES6的new Set()
  • filter
  • 判断逻辑的形式

Module的语法!!!

引入:import

  • 全部引入:
import './script'
  • 按需引入:
import {a,b,c,fun} from './script'
  • 自定义名称引入:
import xxx from './script'
console.log(xxx.a)

抛出:export

export let a = 10

let fun = ()=>{}
export {fun}

let a = 10
let b = 20
export {a,b}

export default {a,b}

Promise!!!

Promise是异步编程的一种解决方案

  • 功能:写异步的代码,同步地执行出来

  • 好处:让代码更好地维护或者易读

  • 同步:只有前一个任务执行完毕了,才能继续执行下一个任务

  • 异步:不进入主线程,进入的是任务队列,只有任务队列通知主线程某个异步任务可以执行,该任务才会进入主线程。

Promise有哪几种状态:

Promise对象代表一个异步操作,有三种状态:pending(进行中),fulfilled(已成功),rejected(已失败)

async和await!!!

async函数返回的是Promise

一般async和await配合起来用:如果单独使用await会报错,await需要在有async的地方用(没有async就没有await)

await就是等待(async wait)的意思,要等标记await的语句执行完才会接着往下执行

简洁:异步编程的最高境界就是不关心它是否是异步。async、await很好的解决了这一点,将异步强行转换为同步处理。

async/await与promise不存在谁代替谁的说法,因为async/await是寄生于Promise,Generater的语法糖。

和Promise的区别

  1. 函数前面多了一个async关键字。await关键字只能用于async定于的函数内。async函数会隐式地返回一个Promise,该promise的resolve值就是return的值。示例中resolve的值就是字符串"aaa"
  2. await的是有使用限制的,await关键字只能用于async定于的函数内,如果未使用async而直接使用await就会抛SyntaxError。

为什么async/await更好?

  1. 使用async函数可以让代码简洁很多,不需要想Promise一样需要then,不需要写匿名函数处理Promise的resolve的值,也不需要定义多余的data变量,还避免了嵌套代码。
  2. async/await 让 try/catch可以同时处理同步和异步的错误。