文章目录

  • 一、前言
  • 二、ES6的相关语法
  • 1、let、const的用法
  • 2、数组和对象的解构
  • 3、模板字符串
  • 4、函数的默认参数和剩余参数
  • 5、箭头函数
  • 6、展开语法
  • 7、Symbol的使用
  • 8、Set和WeakSet
  • 9、Map和WeakMap
  • 三、结语


一、前言

JavaScript这门语言在设计之初,其实会存在某些问题,随着JavaScript这门语言越来越流行, ECMA国际标准化组织在ES5的基础上,推出了许多新特性以补充之前不足的地方,使得JavaScript这门语言越来越完善,那么今天我就将讲述一些比较常用的ES6的新特性,(本文主要大致介绍一下有关语法,Promise,ESModule等内容需要较长篇幅,以后会单独写文章介绍)一起来看看吧。
看完本文,你将:
1、你将会了解ES6的常用的语法
2、你将会了解这些语法的常用使用规则
一起来看看吧!

二、ES6的相关语法

1、let、const的用法

在ES6之前是没有块级作用域的,而在ES5只有两个东西会形成作用域:1、全局作用域,2、函数作用域,ES6中的代码块级作用域,对let、const、function、class申明的类型是有效的。另外if、for、switch语句的代码是块级作用域。
let:
实例:加入页面上有4个button按钮

const btns = document.getElementsByTagName('button')

for (var i = 0; i < btns.length; i++) {
    btns[i].onclick = function() {
        console.log("第" + i + "个按钮被点击")//第4个按钮被点击
    }
}
console.log(i)//4

我们可以看到,不管点击哪个按钮,输出的都是“第4个按钮被点击”,为什么会出现这种情况呢?
其中的 i 变量不在函数自身的活动对象中,因此需要向上查找,而此时for循环已经结束,因此访问到的 i 变量值均是4。
如果var 改成let:

const btns = document.getElementsByTagName('button')
for (let i = 0; i < btns.length; i++) {
    btns[i].onclick = function() {
        console.log("第" + i + "个按钮被点击")
    }
}

则点击第一个会输出:第0个按钮被点击,点击第二个会输出:第1个按钮被点击等,达到了我们想要的效果。为什么会这样呢?
首先,let 声明的变量只在声明的{}内有效,所以function () { console.log(“第” + i + “个按钮被点击”)} 在创建时,每次都要声明一个 i 变量,也就是说这个 i 和上一次循环的 i 本质上是不同的变量,每循环一次,就会在内存中创建一个内存地址保存这次i的值,每次循环的i值是不同的变量。而之前采用var声明的时候,由于 i 变量提升,每次的循环其实就是用同一个变量来进行每次加1的操作。

const:
const本质上是传递的值不可以修改
但是如果传递的是一个引用类型(内存地址), 可以通过引用找到对应的对象, 去修改对象内部的属性, 这个是可以的

const obj = {
   foo: "foo"
 }

obj = {}
obj.foo = "aaa"
console.log(obj.foo)//aaa

2、数组和对象的解构

对数组的解构:

var names = ["a", "b", "n"]
// var item1 = names[0]
// var item2 = names[1]
// var item3 = names[2]

// 对数组的解构: []
var [item1, item2, item3] = names
console.log(item1, item2, item3)

// 解构后面的元素
var [, , itemz] = names
console.log(itemz)

// 解构出一个元素,后面的元素放到一个新数组中
var [itemx, ...newNames] = names
console.log(itemx, newNames)

// 解构的默认值
var [itema, itemb, itemc, itemd = "aaa"] = names
console.log(itemd)

对对象的解构:

var obj = {
  name: "why",
  age: 18,
  height: 1.88
}

// 对象的解构: {}
var { name, age, height } = obj
console.log(name, age, height)//why 18 1.88

var { age } = obj
console.log(age)//18

var { name: newName } = obj
console.log(newName)//why

//添加默认值
var { address: newAddress = "广州市" } = obj
console.log(newAddress)


function foo(info) {
  console.log(info.name, info.age)
}

foo(obj)//why 18

function bar({name, age}) {
  console.log(name, age)
}

bar(obj)//why 18

3、模板字符串

模板字符串最外层用``嵌套,l=当引用变量时,用${变量名}代替,里面可以写变量,可以对变量进行基本的算术运算,也可以写函数的执行结果。实例如下:

// ES6之前拼接字符串和其他标识符
const name = "why"
const age = 18
const height = 1.88

// console.log("my name is " + name + ", age is " + age + ", height is " + height)

// ES6提供模板字符串 ``
const message = `my name is ${name}, age is ${age}, height is ${height}`
console.log(message)

const info = `age double is ${age * 2}`
console.log(info)

function doubleAge() {
  return age * 2
}

const info2 = `double age is ${doubleAge()}`
console.log(info2)

另外补充一点,调用函数的方式: 标签模块字符串:

// 第一个参数依然是模块字符串中整个字符串, 只是被切成多块,放到了一个数组中
// 第二个参数是模块字符串中, 第一个 ${}
function foo(m, n, x) {
  console.log(m, n, x, '---------')
}

// foo("Hello", "World")

// 另外调用函数的方式: 标签模块字符串
// foo``

// foo`Hello World`
const name = "why"
const age = 18
// ['Hello', 'Wo', 'rld']
foo`Hello${name}Wo${age}rld`//[ 'Hello', 'Wo', 'rld' ] why 18 ---------

有了模板字符串后,再也不用担心用+加双引号拼接字符串了,是不是很方便呢!

4、函数的默认参数和剩余参数

函数的默认参数:

function foo(m = "aaa", n = "bbb") {
  console.log(m, n)
}

直接在函数参数那里设置即可,如果参数是undefined,便会使用默认参数。设置了默认参数后,函数的length会变

function baz(x, y, z, m, n = 30) {
 console.log(x, y, z, m, n)
 }console.log(baz.length)


只会输出默认参数之前的参数数量,例如本例中,输出4。
函数的剩余参数:
在函数传参数的括号里面使用,只能在括号里面末尾使用,会记录参数除前面的全部参数,以数组方式存储在定义的变量中,看一下例子:

function foo(m, n, ...args) {
    console.log(m, n) //20 30
    console.log(args) //[ 40, 50, 60 ]
    console.log(arguments) //{ '0': 20, '1': 30, '2': 40, '3': 50, '4': 60 }
}
foo(20, 30, 40, 50, 60)

5、箭头函数

格式为()=>{}。箭头函数内部无this和arguments,输出时的值是函数外层的值。箭头函数也没有prototype。

// function foo() {

// }

// console.log(foo.prototype)
// const f = new foo()
// f.__proto__ = foo.prototype

var bar = () => {
  console.log(this, arguments)
}

console.log(bar.prototype)

// bar is not a constructor
const b = new bar()

6、展开语法

使用…对数组或者对象进行展开,相当于去掉外层的数组符号或者对象符号,具体用法看下例:

const names = ["abc", "cba", "nba"]
const name = "why"
const info = {name: "why", age: 18}
// 1.函数调用时
function foo(x, y, z) {
  console.log(x, y, z)
}

// foo.apply(null, names)
foo(...names)//abc cba nba
foo(...name)//w h y

// 2.构造数组时
const newNames = [...names, ...name]
console.log(newNames)//[ 'abc', 'cba', 'nba', 'w', 'h', 'y' ]

// 3.构建对象字面量时ES2018(ES9)
const obj = { ...info, address: "广州市", ...names }
console.log(obj)
// {
//   '0': 'abc',
//   '1': 'cba',
//   '2': 'nba',
//   name: 'why',
//   age: 18,
//   address: '广州市'
// }

补充一点:展开语法进行的是浅拷贝:
对象里面的对象,拷贝的是这个内部对象的地址。而不是新建一块空间存储这个对象。

const info = {
  name: "why",
  friend: { name: "kobe" }
}

const obj = { ...info, name: "coderwhy" }
// console.log(obj)
obj.friend.name = "james"

console.log(info.friend.name)//james

7、Symbol的使用

symbol的实例是唯一的不可变的, 用于确保对象的属性不重复
具体用法以及实例见下:

// 1.ES6之前, 对象的属性名(key)
// var obj = {
//   name: "why",
//   friend: { name: "kobe" },
//   age: 18
// }


// obj['newName'] = "james"
// console.log(obj)


// 2.ES6中Symbol的基本使用
const s1 = Symbol()
const s2 = Symbol()

console.log(s1 === s2)//false

// ES2019(ES10)中, Symbol还有一个描述(description)
const s3 = Symbol("aaa")
console.log(s3.description)//aaa

// 3.Symbol值作为key
// 3.1.在定义对象字面量时使用
const obj = {
  [s1]: "abc",
  [s2]: "cba"
}

// 3.2.新增属性
obj[s3] = "nba"

// 3.3.Object.defineProperty方式
const s4 = Symbol()
Object.defineProperty(obj, s4, {
  enumerable: true,
  configurable: true,
  writable: true,
  value: "mba"
})

console.log(obj[s1], obj[s2], obj[s3], obj[s4])//abc cba nba mba
// 注意: 不能通过.语法获取
// console.log(obj.s1)

// 4.使用Symbol作为key的属性名,在遍历/Object.keys等中是获取不到这些Symbol值
// 需要Object.getOwnPropertySymbols来获取所有Symbol的key
console.log(Object.keys(obj))//[]
console.log(Object.getOwnPropertyNames(obj))//[]
console.log(Object.getOwnPropertySymbols(obj))//[ Symbol(), Symbol(), Symbol(aaa), Symbol() ]
const sKeys = Object.getOwnPropertySymbols(obj)
for (const sKey of sKeys) {
  console.log(obj[sKey])
}
// abc
// cba
// nba
// mba
// 5.Symbol.for(key)/Symbol.keyFor(symbol)
const sa = Symbol.for("aaa")
const sb = Symbol.for("aaa")
console.log(sa === sb)//true

//获取key的值
const key = Symbol.keyFor(sa)
console.log(key)//aaa
const sc = Symbol.for(key)
console.log(sa === sc)//true如果key也相等,则两数相等

8、Set和WeakSet

Set是ES6新增的数据结构:
创建Set结构:

const set = new Set()
set.add(10)
set.add(20)
set.add(40)
set.add(333)

set.add(10)
// 2.添加对象时特别注意:
set.add({})
set.add({}) console.log(set)

对数组进行去重:

const arr = [33, 10, 26, 30, 33, 26]
const arrSet = new Set(arr)
const newArr = [...arrSet]
console.log(newArr)

size属性输出Set的key数量。

Set常用的方法:

  • add(value):添加某个元素,返回Set对象本身;
  • delete(value):从set中删除和这个值相等的元素,返回boolean类型;
  • has(value):判断set中是否存在某个元素,返回boolean类型;
  • clear():清空set中所有的元素,没有返回值;
  • forEach(callback, [, thisArg]):通过forEach遍历set;
// 5.Set的方法
// add
arrSet.add(100) //Set(5) { 33, 10, 26, 30, 100 }
console.log(arrSet)


// delete
arrSet.delete(33)
console.log(arrSet) //Set(4) { 10, 26, 30, 100 }

// has
console.log(arrSet.has(100))

// clear
// arrSet.clear()
console.log(arrSet)

// 6.对Set进行遍历
arrSet.forEach(item => {
    console.log(item)
})

for (const item of arrSet) {
    console.log(item)
}

WeakSet的使用:

  • 1.区别一: 只能存放对象类型
  • 2.区别二: 对对象是一个弱引用

WeakSet常见的方法:

  • add(value):添加某个元素,返回WeakSet对象本身;
  • delete(value):从WeakSet中删除和这个值相等的元素,返回boolean类型;
  • has(value):判断WeakSet中是否存在某个元素,返回boolean类型
    –注意:WeakSet不能遍历
const weakSet = new WeakSet()
let obj = { 
  name: "why"
}
const set = new Set()
// 建立的是强引用
//set.add(obj)

// 建立的是弱引用
weakSet.add(obj)

对弱引用的理解:通常情况下,如果有多个变量指向同一个对象,本例中,有多个变量指向这个对象,在强引用情况下,如果obj赋值为null,即obj不指向这个对象了,那么还有set对象里面的某个变量指向这个对象,这个对象并不会被内存回收。但是,在弱引用情况下,如本例中的weakSet.add(obj),set对象由于对这个obj对象建立的是弱引用,且没有其他强引用指向obj,所以内存会回收obj这个对象,也就是说内存中的垃圾清除策略对弱引用的存在是可有可无,可以忽略的。

js es6 简写 js中es6语法_前端


WeakSet的引用场景:

强制类里面的方法只能通过构造方法构建

const personSet = new WeakSet()
class Person {
  constructor() {
    personSet.add(this)
  }

  running() {
    if (!personSet.has(this)) {
      throw new Error("不能通过非构造方法创建出来的对象调用running方法")
    }
    console.log("running~", this)
  }
}

let p = new Person()
p.running()
p.running.call({name: "why"})//Error: 不能通过非构造方法创建出来的对象调用running方法

9、Map和WeakMap

JavaScript中对象中是不能使用对象来作为key的,ES6新增了一种数据结构Map,可以使用对象类型作为key
Map:
Map的构建和加入元素:

const obj1 = { name: "w" }
const obj2 = { name: "e" }
const map = new Map()
map.set(obj1, "aaa")
map.set(obj2, "bbb")
map.set(1, "ccc")
console.log(map)
//Map(3) {
//   { name: 'w' } => 'aaa',
//   { name: 'e' } => 'bbb',
//   1 => 'ccc'
// }

Map常见的方法:

  • set(key, value):在Map中添加key、value,并且返回整个Map对象;
  • get(key):根据key获取Map中的value;
  • has(key):判断是否包括某一个key,返回Boolean类型;
  • delete(key):根据key删除一个键值对,返回Boolean类型;
  • clear():清空所有的元素;
  • forEach(callback, [, thisArg]):通过forEach遍历Map
const map2 = new Map([[obj1, "aaa"], [obj2, "bbb"], [2, "ddd"]])
console.log(map2)
console.log(map2.size)

// set设置属性和值
map2.set("why", "eee")
console.log(map2)

// get(key)获取属性的值
console.log(map2.get("why"))

// has(key)判断是否有属性
console.log(map2.has("why"))

// delete(key)删除某个属性以及值
map2.delete("why")
console.log(map2)

// clear清空Map
// map2.clear()
// console.log(map2)

// 4.遍历map
map2.forEach((item, key) => {
  console.log(item, key)
})

for (const item of map2) {
  console.log(item[0], item[1])
}

for (const [key, value] of map2) {
  console.log(key, value)
}

WeakMap:

  • 区别一: WeakMap不能使用基本数据类型,WeakMap的key只能使用对象,Set可以使用数字、字符串等基本数据类型
  • 区别二:WeakMap的key对对象的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象

WeakMap常见的方法有四个:

  • set(key, value):在Map中添加key、value,并且返回整个Map对象;
  • get(key):根据key获取Map中的value;
  • has(key):判断是否包括某一个key,返回Boolean类型;
  • delete(key):根据key删除一个键值对,返回Boolean类型
  • -注意: WeakMap也是不能遍历的
const obj = {name: "obj1"}
const weakMap = new WeakMap()
weakMap.set(obj, "aaa")
// get方法
console.log(weakMap.get(obj))

// has方法
console.log(weakMap.has(obj))

// delete方法
console.log(weakMap.delete(obj))
// WeakMap { <items unknown> }
console.log(weakMap)

三、结语

关于ES6的相关常用语法就介绍到这里了,想了解剩下的ES7~12的相关语法,请移步主页看下篇,谢谢