0


【汇总】ES6~12的常用语法详解(上篇ES6)

在这里插入图片描述

文章目录

一、前言

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.88var{ age }= obj
console.log(age)//18var{name: newName }= obj
console.log(newName)//why//添加默认值var{address: newAddress ="广州市"}= obj
console.log(newAddress)functionfoo(info){
  console.log(info.name, info.age)}foo(obj)//why 18functionbar({name, age}){
  console.log(name, age)}bar(obj)//why 18

3、模板字符串

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

// ES6之前拼接字符串和其他标识符const name ="why"const age =18const 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)functiondoubleAge(){return age *2}const info2 =`double age is ${doubleAge()}`
console.log(info2)

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

// 第一个参数依然是模块字符串中整个字符串, 只是被切成多块,放到了一个数组中// 第二个参数是模块字符串中, 第一个 ${}functionfoo(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、函数的默认参数和剩余参数

函数的默认参数:

functionfoo(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。
函数的剩余参数:
在函数传参数的括号里面使用,只能在括号里面末尾使用,会记录参数除前面的全部参数,以数组方式存储在定义的变量中,看一下例子:

functionfoo(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.prototypevarbar=()=>{
  console.log(this, arguments)}

console.log(bar.prototype)// bar is not a constructorconst b =newbar()

6、展开语法

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

const names =["abc","cba","nba"]const name ="why"const info ={name:"why",age:18}// 1.函数调用时functionfoo(x, y, z){
  console.log(x, y, z)}// foo.apply(null, names)foo(...names)//abc cba nbafoo(...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)//aaaconst sc = Symbol.for(key)
console.log(sa === sc)//true如果key也相等,则两数相等

8、Set和WeakSet

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

const set =newSet()
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 =newSet(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 =newWeakSet()let obj ={name:"why"}const set =newSet()// 建立的是强引用//set.add(obj)// 建立的是弱引用
weakSet.add(obj)

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

const personSet =newWeakSet()classPerson{constructor(){
    personSet.add(this)}running(){if(!personSet.has(this)){thrownewError("不能通过非构造方法创建出来的对象调用running方法")}
    console.log("running~",this)}}let p =newPerson()
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 =newMap()
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 =newMap([[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 =newWeakMap()
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的相关语法,请移步主页看下篇,谢谢

标签: javascript 前端

本文转载自: https://blog.csdn.net/weixin_50926010/article/details/124521315
版权归原作者 既白biu 所有, 如有侵权,请联系我们删除。

“【汇总】ES6~12的常用语法详解(上篇ES6)”的评论:

还没有评论