5分钟快速了解 ES6 新特性!

163 阅读5分钟

简单总结了一下,其实只是语法层面的变化,内部并没有什么区别

ES6「类」与「继承」
关于JS解构赋值


var、let、const

var 和 let 的区别

都是用来声明变量

var 没有块级作用域,会导致一些不必要的麻烦

let 有块级作用域,是更完美的 var

我基本不用var

1. var 可声明前置

并且可以重复声明

a = 1
var a
var a = 2
// 不报错

2. let 不可以声明前置

a = 1
let a
// 报错

3. let 不可重复声明

let a = 1
let a = 2
// 报错
let a = 1
var a = 2
// 报错 

4. let 存在块级作用域

作用域可以认为是两个大括号之间的区域

function fn() {
  let a = 1
  console.log(a)
}
console.log(a)
// 报错

5. let 暂时性死区

在 let 声明变量之前都是该变量的死区,在死区内不可使用该变量

这也需要拿出来说?

const

用来声明常量

拥有 let 的特性,但是被声明的常量必须赋值,而且值不可改变!

被 const 声明的常量不可改变

示例1:
const a = 1
a = 2 // 报错

能理解!简单嘛!

示例2:
const obj = { a: 1 }
obj.a = 2 			// 不报错
obj = { a: 2 } 	// 报错

啊你骗人,你明明说了不可改变,那为什么 obj.a = 2 不报错?!?!

我们先来说说示例1:

示例1的 a 是简单类型,所以直接赋值的话,相当于改变 a 的值

再说说示例2:

  1. 这里的 obj 是属于复杂类型,或者引用类型的时候,那 obj 存的就是 { a: 1 } 的地址啊!那只要地址不变,那就没有问题啊!

那给 obj.a = 2,那 obj 里面存的地址变没变啊?

因为指向的还是这个对象,只不过对象里面的东西发生了改变。

  1. 但是这么写 obj = { a: 2 },这个意思是我新生成了个对象,然后赋值给 obj,那这个 obj 的地址是不是变了呀?那就会报错嘛!

哦哦...似懂非懂

小结

  • 请大量地使用 let,你都用 ES6 的语法了,还用什么 var
  • 你觉得不可变的,那就用 const,比如引用一个模块、定义一个全局的url

解构赋值

按照一定模式,从数组和对象中提取值变量,对变量进行赋值,直接看代码!

数组的解构赋值

1. 基本用法

// ES5 写法
let a = 1
let b = 2
let c = 3
// 或
let a = 1, b = 2, c = 3

// ES6 解构赋值
let [a, b, c] = [1, 2, 3]

// 这种情况下,只要值对应得上,依然可以解构
let [a, b] = [1, 2, 3]
let [a, [b], c] = [1, [2], 4]

// 这种就直接报错啦,左边是个数组,右边都不是数组
let [a] = 1;

2. 默认值

跟函数的默认参数类似,哦?没学过?后面会说 链接

let [a] = [1]
// 1

let [a] = []
// undefined   不设置默认值,默认等于undefined

let [a, b = 2] = [1]
// 1 2

let [a = 1, b = 2] = [2]
// 2 2

let [a, b = 2] = [1, 3]
// 1 3

let [a = 1] = []
// 1

let [a = 1] = [null]
// null   因为 null 不严格等于 undefined,所以默认值不生效

默认值:设置了,就用你设置的;没设置,就用 undefined

对象的解构赋值

前置知识

let [name, age] = ['heycn', 22]
let a = { name, age }
// 等同于
let a = { name: name, age: age }

1. 基本用法

let { name, age } = { name: 'heycn', age: 22 }
name	// "heycn"
age		// 22

2. 默认值

不设置,默认值就是 undefined!

let { x, y = 2 } = { x: 1 }
x // 1
y // 2

函数的解构赋值

function add([a, b] = [1, 2]) {
  return a + b
}
add() // 3

作用

// 我在 vscode 写完格式的话的时候,vscode 会有骚操作,请在浏览器上运行!
let [x, y] = [1, 2]; 一定要加分号!这是在数组前面!
[x, y] = [y, x]
// [2, 1]

字符串、数组、函数、对象

字符串

1. 多行字符串

let str = `
Hi
这是多行字符串
是不是很方便
`
// 但是在转义后的时候会有问题

2. 模板字符串

可以更方便的拼接啦!

let name = 'heycn'
let helloWorld = `我是${name}`
helloWorld // "我是heycn"

数组

1. 拓展运算符

也叫展开运算符,将一个数组转为用逗号分隔的参数序列,可以更方便的插入

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

let a = [1, 2, 3]
let b = [...a, 4, 5]
b // [1, 2, 3, 4, 5]

2. 运用:函数参数的拓展

function sort(...arr) {
  console.log(arr.sort())
}
sort(2, 4, 1, 3)
// [1, 2, 3, 4]

3. 运用:类数组对象转数组

let ps = document.querySelectorAll('p')
Array.from(ps).forEach(p => {
  console.log(p.innerText)
})

[...p].forEach(p=>{console.log(p.innerText)})

函数

1. 函数的默认值

设置了,就用你设置的;没设置,就用 undefined

很好理解,没什么好讲

function myName(name = 'heycn') {
  console.log(`My name is ${name}`)
}
myName() 				// My name is heycn
myName('小陈') 	// My name is 小陈

2. 函数的默认值:这两种写法的区别?

多看两遍就能悟出来了

// 函数 fn1
function fn1({ x = 0, y = 0 } = {}) {
  return [x, y]
}

// 函数 fn2
function fn2({ x, y } = { x: 0, y: 0 }) {
  return [x, y]
}

// 函数没有参数的情况
fn1() // [0, 0]
fn2() // [0, 0]

// x 和 y 都有值的情况
fn1({ x: 3, y: 8 }) // [3, 8]
fn2({ x: 3, y: 8 }) // [3, 8]

// x 有值,y 无值的情况
fn1({ x: 3 }) // [3, 0]
fn2({ x: 3 }) // [3, undefined]

// x 和 y 都无值的情况
fn1({}) // [0, 0]
fn2({}) // [undefined, undefined]

// 传递新的东西
fn1({ z: 3 }) // [0, 0]
fn2({ z: 3 }) // [undefined, undefined]
  • fn1:调用函数需要你传递一个对象,如果你没有传对象就是用**默认值对象 {} **,默认值对象里面都是 undefined
  • fn2:参数需要是一个对象,如果没传对象,就是用默认值对象 { x: 0, y: 0} ,如果传了对象,就使用你传递的对象

3. 箭头函数

箭头函数没有没有 this 一开始看会有点不适应,多写就能明白了

let fn = n => {n + 1} // 只有一个参数的话,小括号可以省略
// 等价于
let fn = function (n) {return n + 1}

let fn = () => 1 // 注意对比返回值
// 等价于
let fn = function () {return 1}

let fn = (a, b) => a + b // 看出区别了吗,直接 return 可以省略大括号
// 等价于
let fn = function (a, b) {return a + b}

对象

1. 属性的简写

let name = 'heycn'
let age = 22
let people = { name, age }
// {name: "heycn", age: 22}

2. 函数的简写

let helloWorld = {
  hello() {
    console.log('Hello')
  },
  world() {
    console.log('World')
  }
}
helloWorld.hello() // Hello
helloWorld.world() // World

模块:导出与导入

ES6 在导入和导出方面又有哪些改变呢?

导出

1. 写法1

// index.js
export let name = 'heycn'
export let age = '22'
export function getName() {}

2. 写法2

// index.js
let name = 'heycn'
let age = '22'
export function getName() {}
export { name, age, getName }

3. 默认导出

export default

// index.js
export default function () {
  console.log('HelloWorld')
}

导入

1. 示例1

import { name, age, getName } from './index.js' // 这也相当于是个解构赋值

2. 导入 - 默认导出的模块

import fn from './index.js'

类 和 继承

说实话 这我很少用啊...可是面试会被问啊!

1. 构造函数

class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }

  sayHello() {
    console.log(`hello, ${this.name}, i am ${this.age} years old`)
  }
}

2. 静态方法

class EventCenter {
  static fire() {
    return 'fire'
  }
  static on() {
    return 'on'
  }
}

继承

多写几遍就行了

class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }

  sayHello() {
    console.log(`hello, ${this.name}, i am ${this.age} years old`)
  }
}

class Student extends Person {
  constructor(name, age, score) {
    super(name, age)
    this.score = score
  }
  sayScore() {
    console.log(`hello, ${this.name}, i am ${this.age} years old, i get ${this.score}`)
  }
}