ES6,也称ESMAScript2015,这个版本增加了很多好用的特性

变量声明

ES6之前用var来定义变量,ES6增加了两个变量声明的方式,分别为const和let,const用来定义常量,let用于定义变量,弥补了使用var来定义的漏洞。

  • var 有变量提升,在全局/函数中定义的变量都会被提升到全局/函数的最上方,值为undefined
  • var 没有块级作用域的概念,通过 if / for /switch 定义的变量都会被提升到全局
  • let 定义变量,可被修改,不可被重复声明,有块级作用域
  • const 定义常量,定义时需赋值,不可被修改,不可被重复声明,有块级作用域

他们三者主要区别如下

初始化需赋值 变量提升 重复声明 重新赋值 块级作用域 跨块访问 跨函数访问
var × × ×
let × × × × ×
const × × × × ×

let和const在定义之前会将变量保存到变量环境中,但是不可被访问。

let userName = 'alice'
if (true) {
  console.log(userName)
  let userName = 'kiki'
}

以上代码的执行结果如下

在以上代码中,通过if创建的块级作用中有userName变量,虽然全局中也有userName变量,但是此时块中已经通过let定义已经保存到了块的变量环境中,会直接从块中获取,但在赋值之前仍然是无法访问的,所以就存在了一个【暂时性死区(temporal dead zone)】的问题

字面量增强

在对象中,属性的定义有了更简洁的方式。

  • 对象中定义的属性key和value一致时,可以合并
  • 方法简写可以去掉function声明
  • 对象中的属性可以通过[]来定义非字符串的变量
var name = 'alice'
var age = 18
var info = 'hobby' var user = {
  name: name,
  age: age,
  eating: function () {
    console.log('user eating~')
  }
}
user[info + 's'] = 'swimming' const person = {
  name,
  age,
  eating() {
    console.log('person eating~')
  },
  [info + 's']: 'swimming'
} console.log(user)
console.log(person)

以上两种定义对象的方式最终效果是一致的

解构

数组解构

当我们想要获取数组的元素时,很多时候都会通过下标值,es6给我们提供了一种解构的方式,通过下标值的一一对应来获取每一个元素

//通过下标值获取元素
var names = ['alice', 'kiki', 'macus']
var x = names[0]
var y = names[1]
var z = names[2]
console.log(x, y, z) // 解构
var [a, b, c] = names
console.log(a, b, c) // 当只需要后两位元素时,第一个元素空着
var [, m, n] = names
console.log(m,n) // 当只对应了一个元素时,使用剩余参数放置到一个数组里
var [x, ...list] = names
console.log(x, list)

执行结果如下

通过babel将es6代码编译成es5代码可以发现,数组解构还是通过下标值来获取元素

对象解构

当获取对象的value时,我们通常使用 .key 或者 [key],es6对于对象也提供了更为简便的解构的方式,需注意解构出来的变量要与key值相对应

var user = {
  name: 'alice',
  age: 20
}
console.log(user.name, user.age) var { name, age } = user
console.log(name, age)

以上两种获取属性值的方式结果一致

通过babel将es6代码编译成es5代码可以发现,对象解构的原理还是对象.属性名的形式

模板字符串

在没有模板字符串之前,拼接字符串和变量需要用引号(""),代码的可读性比较弱,增加了模板字符之后,可以直接在``中写字符串,通过 ${expression} 来嵌入动态的内容

const name = 'aclie'
const age = 18
const user = 'My name is ' + name + ' and i am ' + age + ' years old.'
const person = `My name is ${name} and i am ${age} years old.` console.log(user)
console.log(person)

以上两种定义变量的方式结果是一致的

``中还可以拼接函数的执行结果

function getAnimalName(){
  return 'cat'
}
const animal = 'This is a ' + getAnimalName()
const pet = `This is a ${getAnimalName()}` console.log(animal)
console.log(pet)

通过 + 号拼接和模板字符串是一样的结果

``还可以用来调用函数,通过模板字符串来分割传参

const name = 'aclie'
const age = 18
function foo(a, b, c, d) {
  console.log(a)
  console.log(b)
  console.log(c)
  console.log(d)
}
foo`1${name}2${age}3${100}`

每个模板字符串中的数据对应传入函数的一个参数,分割的剩余数据组成一个数组作为参数

模板字符串转es5代码的实现是通过字符串的concat方法进行拼接

函数的默认参数

在es6以前需要自己判断函数有没有入参,没有就将入参的变量赋值为一个初始化的值

function getUserInfo(name, age){
  name = name || 'kiki'
  age = age || 18
  console.log(name,age)
}
getUserInfo('', 0) function getPersonInfo(name = 'alice', age = 18){
  console.log(name, age)
}
getPersonInfo('alice', 0)

如果有 || 运算符时,当传入参数为空字符串或者0时,将被认为是false后执行 || 运算符后的代码

使用函数的默认参数还可以解构对象

function getUserInfo({ name, age } = { name: 'kiki', age: 18 }) {
  console.log(name, age)
}
getUserInfo() function getPersonInfo({name = 'kiki', age = 18} = {}){
  console.log(name, age)
}
getPersonInfo()

两种方式解构出来的结果是一样的

通过babel编译函数的默认参数发现是通过arguments来进行处理的

剩余参数

在es6之前,获取函数的所有入参可以通过arguments,es6增加了剩余参数的语法用来指代没有被对应形参的实参

function foo(a, b, ...rest) {
console.log('arguments', arguments)
  console.log(a, b, rest)
}
foo(1, 2, 3, 4, 5, 6)

通过 ...的运算符来获取剩余参数

arguments和剩余参数还是有一些不同之处的

  • 通过arguments可以获取所有的实参,而剩余参数只能获取没有被对应到形参的实参,而且箭头函数中是没有arguments的
  • arguments的数据结构像数组,但它并不是真正的数组,是不可以直接使用数组的方法的,而剩余参数就是一个数组,可直接使用数组方法

剩余参数通过babel编译成可兼容浏览器的es5语法时,是通过创建数组逐一添加通过arguments获取的数据

展开语法

展开语法也是通过 ... 来进行对数据的操作,展开语法有三个应用场景

  • 函数调用时
  • 数组构造时
  • 构建对象字面量时(ES9语法)
const array = [1, 2, 3]
const obj = { name: 'alice', age: 20}
const name = 'kiki' // 函数调用
function foo(a, b, c){
  console.log(a, b, c)
}
foo(...array)
foo(...name) // 数组构建
const newArr = [...array, 4, 5]
console.log(newArr) // 构建对象字面量
const newObj = {...obj, name: 'kiki'}
console.log(newObj)

可通过展开语法展开对象、数组、字符串

需要注意的是,展开语法实际上是浅拷贝

const user = { name: 'alice', favorite: { sport: 'tennis'}}
const newUser = {...user}
newUser.name = 'kiki'
newUser.favorite.sport = 'football'
console.log(user)

user中favorite属性是一个对象,由user通过展开语法创建的newUser对象修改了对象中的属性,原来的user对象的favorite属性也会更改

它们在内存中的表现如下图所示

数组和函数的展开语法通过babel编译比较简单,分别是通过concat方法和apply第二个参数可传数组的特性,对象的展开语法复杂一些,有一些函数封装和逻辑判断,就没有截图了

数值的表示

规定了进制的表示方式

  • 二进制数据,以 0b 开头,每一位数字最大值为1
  • 八进制数据,以 0o 开头,每一位数字最大值为7
  • 十六进制数据,以 0x 开头,A-F表示数字10-15,每一位数字最大值为F
const a = 0b100
const b = 0o100
const c = 0x100 console.log(a, b, c)

最后还是会转换成十进制数据

Symbol

Symbol表示唯一的值,是一种新的数据类型,对象中的key值在此之前只能使用字符串,如果key值相同的情况下会进行覆盖,但使用Symbol就不会出现覆盖的情况。

Symbol定义时,还有一些注意事项

  • 通过Symbol声明的变量可以在括号里定义一个描述,通过description来获取(ES10添加的)
  • Symbol定义的变量即使有相同的descripton也不会重复
  • Symbol.for定义的变量在全局,可通过Symbol.keyFor查找,有相同的descrition时指向同一个元素
  • Symbol作为对象中的key值时,需要使用 [],不能使用 . 来赋值
const a = Symbol('hello')
const b = Symbol('hello')
const c = Symbol.for('alice')
const d = Symbol.for('alice') const obj = {
  [a]: 'alice'
}
obj[b] = 'kiki'
Object.defineProperty(obj, c, {
  value: 'macus'
}) console.log(a)
console.log(a.description)
console.log(a === b)
console.log(c === d)
console.log(Symbol.keyFor(a), Symbol.keyFor(c))
console.log(obj[a], obj[b], obj[c])

执行结果如下

Set和WeakSet

Set

Set意思是集合,类似于数组,但它存储的元素不能重复。

Set有这些属性和方法

  • size:返回Set中元素的个数
  • add(value):添加某个元素,返回Set对象本身
  • delete(value):从set中删除和这个值相等的元素,返回boolean类型
  • has(value):判断set中是否存在某个元素,返回boolean类型
  • clear():清空set中所有的元素,没有返回值
  • forEach(callback, [, thisArg]):通过forEach遍历set
  • 支持for / for of的遍历
const arr = [{ name: "alice" }, 2, 3, 4, 5, 4, 3, 2, 1]
const set = new Set(arr) set.add(0)
set.delete(3) console.log(set.size)
console.log(set.has(1))
console.log(set)
console.log([...set])
console.log(Array.from(set)) for (let item of set) {
  console.log(item)
}
set.forEach(item => {
  console.log(item)
})

执行结果如下

WeakSet

还有一个与Set类似的数据结构叫WeakSet,它和Set的区别在于

  • WeakSet中只能存放对象类型,不能存放基本数据类型
  • WeakSet对元素是弱引用,如果没有其他引用对某个对象进行引用,那么垃圾回收器(GC)可以对该对象进行回收

它有这些方法

  • add(value):添加某个元素,返回WeakSet对象本身
  • delete(value):从WeakSet中删除和这个值相等的元素,返回boolean类型
  • has(value):判断WeakSet中是否存在某个元素,返回boolean类型
const student = { grade: 4 }
let person = { hobby: 'running' }
const arr = [student, person]
const weakSet = new WeakSet(arr) weakSet.add({ grade: 4 })
weakSet.delete(student)
console.log(weakSet.has(student))
console.log(weakSet)

因为WeakSet对元素是弱引用,引入的内容可能被GC回收,所以是不能够遍历和使用toString()方法获取元素的

当set中存储的对象由内存地址0x100改为指向null时,原来的内存地址0x100不会被垃圾回收器回收,因为set中是强引用,而weakMap中存储的对象由内存地址0x200改为指向null时,原来的内存地址0x200会被垃圾回收器回收,因为weakSet中是强引用

Map和WeakMap

Map

Map表示字典存储映射关系,类似于对象,但对象中的Key数据类型只能为字符串或者Symbol,在Map中就没有限制

Map常见的属性和方法

  • size:返回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
  • 可以通过for of进行遍历

const user = { name: 'alice' }
const info = { message: 'hello' }
const map = new Map()
map.set(user, info) // map.clear()
console.log(map.size)
console.log(map.has(user))
console.log(map.get(user))
console.log(map) map.forEach((value, key)=>{
  console.log(value, key)
}) for(let [key, value] of map){
  console.log('item', key, value)
}

执行结果如下

WeakMap

与Map类似,但有一些区别(与set 和 WeakSet中的区别类似)

  • WeakMap的key只能使用对象,不接受其他的类型作为key
  • WeakMap的key对对象想的引用是弱引用,如果没有其他引用引用这个对象, 那么垃圾回收器(GC)可以回收该对象

它有这些方法

  • set(key, value):在Map中添加key、value,并且返回整个Map对象
  • get(key):根据key获取Map中的value
  • has(key):判断是否包括某一个key,返回Boolean类型
  • delete(key):根据key删除一个键值对,返回Boolean类型

因为WeakMap对元素是弱引用,引入的内容可能被GC回收,所以是不能够遍历和使用toString()方法获取元素的

以上就是ES6包含的大部分属性,关于js高级,还有很多需要开发者掌握的地方,可以看看我写的其他博文,持续更新中~

你知道ES6中的这些属性吗的更多相关文章

  1. ES6中object对象属性

    //////es5中定义对象属性要么字面量.要么点.要么[],变量与空格在这些方法中没有得到好的支持 /////在es6中可以这么定义: let w='www'; let obj1={w};//obj ...

  2. es6中顶层对象属性≠全局属性

    先思考一下下面代码的输出结果是什么 const a = { x:1, fn:()=>this.x+=1 } const x = 1 a.fn() console.log(a.x,x) 正确答案为 ...

  3. es6中的属性名表达式

    代码如下: 问题: 为什么我可以这样给obj1对象添加动态属性? 为什么我最终的结果是只添加了right属性? 解答: 1. 第一个问题解答如下: 我们知道在es5中给对象添加属性有两种方法,一种是通 ...

  4. Nodejs与ES6系列4:ES6中的类

    ES6中的类 4.1.class基本语法 在之前的javascript语法中是不存在class这样的概念,如果要通过构造函数生成一个新对象代码 function Shape(width,height) ...

  5. ES6中Arguments和Parameters用法解析

    原文链接 译文 ECMAScript 6 (也称 ECMAScript 2015) 是ECMAScript 标准的最新版本,显著地完善了JS中参数的处理方式.除了其它新特性外,我们还可以使用rest参 ...

  6. ES6中的Class

    对于javascript来说,类是一种可选(而不是必须)的设计模式,而且在JavaScript这样的[[Prototype]] 语言中实现类是很蹩脚的. 这种蹩脚的感觉不只是来源于语法,虽然语法是很重 ...

  7. ES5和ES6中对于继承的实现方法

    在ES5继承的实现非常有趣的,由于没有传统面向对象类的概念,Javascript利用原型链的特性来实现继承,这其中有很多的属性指向和需要注意的地方. 原型链的特点和实现已经在之前的一篇整理说过了,就是 ...

  8. ES6中的高阶函数:如同 a => b => c 一样简单

    作者:Sequoia McDowell 2016年01月16日 ES6来啦!随着越来越多的代码库和思潮引领者开始在他们的代码中使用ES6,以往被认为是"仅需了解"的ES6特性变成了 ...

  9. 深入理解 JavaScript 异步系列(3)—— ES6 中的 Promise

    第一部分,Promise 加入 ES6 标准 原文地址 http://www.cnblogs.com/wangfupeng1988/p/6515855.html 未经作者允许不得转载! 从 jquer ...

  10. ES6中的Symbol类型

    前面的话 ES5中包含5种原始类型:字符串.数字.布尔值.null和undefined.ES6引入了第6种原始类型——Symbol ES5的对象属性名都是字符串,很容易造成属性名冲突.比如,使用了一个 ...

随机推荐

  1. 2023-03-16:给定一个由 0 和 1 组成的数组 arr ,将数组分成 3 个非空的部分, 使得所有这些部分表示相同的二进制值。 如果可以做到,请返回任何 [i, j],其中 i+1 < j

    2023-03-16:给定一个由 0 和 1 组成的数组 arr ,将数组分成 3 个非空的部分, 使得所有这些部分表示相同的二进制值. 如果可以做到,请返回任何 [i, j],其中 i+1 < ...

  2. 记录内网Docker启动Stable-Diffusion遇到的几个坑

    摘要:最近看到K8s启动stable-diffusion的文章,想着在自己开发环境复现一下.没想到在内网环境还遇到这么多问题,记录一下. 本文分享自华为云社区<内网Docker启动Stable- ...

  3. Python从0到1丨了解图像形态学运算中腐蚀和膨胀

    摘要:这篇文章将详细讲解图像形态学知识,主要介绍图像腐蚀处理和膨胀处理. 本文分享自华为云社区<[Python从零到壹] 四十七.图像增强及运算篇之腐蚀和膨胀详解>,作者: eastmou ...

  4. Python基础 - 标识符命名规范

    标识符是什么? 标识符主要用来给变量名,函数名,方法名,类名起名时要遵循的规范 硬性规则   见名知意(使用中文转译后的英文)  由字母,数字,下划线组成, 并且不能以数字开头, 不能和Python关 ...

  5. 为teamcity的代码语法检查工具pyflakes增加支持python2和python3

    TeamCity和pyflakes TeamCity是一款由JetBrains公司开发的持续集成和部署工具,它提供了丰富的功能来帮助团队协作进行软件开发.其中包括代码检查.自动化构建.测试运行.版本控 ...

  6. 如何制作 Storybook Day 网页上的 3D 效果?

    Storybook 刚刚达到了一个重要的里程牌:7.0 版本!为了庆祝,该团队举办了他们的第一次用户大会 - Storybook Day.为了更特别,在活动页面中添加了一个视觉上令人惊叹的 3D 插图 ...

  7. THM武器化

    Weaponization thm:https://tryhackme.com/room/weaponization 武器化 了解和探索常见的红队武器化技术.您将学习使用业内常见的方法构建自定义有效载 ...

  8. uniapp主题切换功能的第一种实现方式(scss变量+vuex)

    随着用户端体验的不断提升,很多应用在上线的时候都要求做不同的主题,最基本的就是白天与夜间主题. 就像b站app主题切换,像这样的 uniapp因为能轻松实现多端发布而得到很多开发者的青睐,但每个端的实 ...

  9. Dotnet9网站回归Blazor重构,访问速度飞快,交互也更便利了!

    大家好,我是沙漠尽头的狼. Dotnet9网站回归Blazor重构,访问速度确实飞快,同时用上Blazor的交互能力,站长也同步添加了几个在线工具,这篇文章分享下Blazor的重构过程,希望对大家网站 ...

  10. Java 设计模式实战系列—工厂模式

    在 Java 开发中,对象的创建是一个常见的场景,如果对象的创建和使用都写在一起,代码的耦合度高,也不利于后期的维护.我们可以使用工厂模式来解决这个问题,工厂模式是一个创建型模式,将对象的创建和使用分 ...