工作中常用到的ES6语法


Posted in Javascript onSeptember 04, 2018

什么是ES6?

ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。Mozilla公司将在这个标准的基础上,推出JavaScript 2.0。

ECMAScript和JavaScript到底是什么关系?很多初学者会感到困惑,简单来说,ECMAScript是JavaScript语言的国际标准,JavaScript是ECMAScript的实现。

一、let和const

在JavaScript中咱们以前主要用关键var来定义变量,ES6之后,新增了定义变量的两个关键字,分别是let和const。

对于变量来说,在ES5中var定义的变量会提升到作用域中所有的函数与语句前面,而ES6中let定义的变量则不会,let声明的变量会在其相应的代码块中建立一个暂时性死区,直至变量被声明。

let和const都能够声明块级作用域,用法和var是类似的,let的特点是不会变量提升,而是被锁在当前块中。

一个非常简单的例子:

function test() {
if(true) {
 console.log(a)//TDZ,俗称临时死区,用来描述变量不提升的现象
 let a = 1
}
}
test() // a is not defined

function test() {
 if(true) {
  let a = 1
 }
 console.log(a)
} 
test() // a is not defined

唯一正确的使用方法:先声明,再访问。

function test() {
 if(true) {
  let a = 1
  console.log(a)
 }
}
test() // 1

const

声明常量,一旦声明,不可更改,而且常量必须初始化赋值。

const虽然是常量,不允许修改默认赋值,但如果定义的是对象Object,那么可以修改对象内部的属性值。

const type = {
 a: 1
}
type.a = 2 //没有直接修改type的值,而是修改type.a的属性值,这是允许的。
console.log(type) // {a: 2}

const和let的异同点

相同点:const和let都是在当前块内有效,执行到块外会被销毁,也不存在变量提升(TDZ),不能重复声明。

不同点:const不能再赋值,let声明的变量可以重复赋值。
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

块级作用域的使用场景

除了上面提到的常用声明方式,我们还可以在循环中使用,最出名的一道面试题:循环中定时器闭包的考题
在for循环中使用var声明的循环变量,会跳出循环体污染当前的函数。

for(var i = 0; i < 5; i++) {
 setTimeout(() => {
 console.log(i) //5, 5, 5, 5, 5
 }, 0)
}
console.log(i) //5 i跳出循环体污染外部函数

//将var改成let之后
for(let i = 0; i < 5; i++) {
 setTimeout(() => {
 console.log(i) // 0,1,2,3,4
 }, 0)
}
console.log(i)//i is not defined i无法污染外部函数

在实际开发中,我们选择使用var、let还是const,取决于我们的变量是不是需要更新,通常我们希望变量保证不被恶意修改,而使用大量的const。使用const声明,声明一个对象的时候,也推荐使用const,当你需要修改声明的变量值时,使用let,var能用的场景都可以使用let替代。

symbol

ES6 以前,我们知道5种基本数据类型分别是Undefined,Null,Boolean,Number以及String,然后加上一种引用类型Object构成了JavaScript中所有的数据类型,但是ES6出来之后,新增了一种数据类型,名叫symbol,像它的名字表露的一样,意味着独一无二,意思是每个 Symbol类型都是独一无二的,不与其它 Symbol 重复。
可以通过调用 Symbol() 方法将创建一个新的 Symbol 类型的值,这个值独一无二,不与任何值相等。

var mySymbol=Symbol();
console.log(typeof mySymbol) //"symbol"

二、字符串

ES6字符串新增的方法

UTF-16码位:ES6强制使用UTF-16字符串编码。关于UTF-16的解释请自行百度了解。

codePointAt():该方法支持UTF-16,接受编码单元的位置而非字符串位置作为参数,返回与字符串中给定位置对应的码位,即一个整数值。

String.fromCodePoiont():作用与codePointAt相反,检索字符串中某个字符的码位,也可以根据指定的码位生成一个字符。

normalize():提供Unicode的标准形式,接受一个可选的字符串参数,指明应用某种Unicode标准形式。

在ES6中,新增了3个新方法。每个方法都接收2个参数,需要检测的子字符串,以及开始匹配的索引位置。

模板字符串

字符串是JavaScript中基本类型之一,应该算是除了对象之外是使用最为频繁的类型吧,字符串中包含了例如substr,replace,indexOf,slice等等诸多方法,ES6引入了模板字符串的特性,用反引号来表示,可以表示多行字符串以及做到文本插值(利用模板占位符)。

// 以前的多行字符串我们这么写:
console.log("hello world 1\n\
hello cala");
// "hello world
// hello cala"

//有了模板字符串之后
console.log(`hello world
string text line 2`);
// "hello world
// hello cala"

可以用${}来表示模板占位符,可以将你已经定义好的变量传进括弧中,例如:

var name="cala";
var age=22;
console.log(`hello,I'am ${name},my age is ${age}`)
//hello,I'am cala,my age is 22
includes(str, index):如果在字符串中检测到指定文本,返回true,否则false。

let t = 'abcdefg'
if(t.includes('cde')) {
 console.log(2)
}
//true
startsWith(str, index):如果在字符串起始部分检测到指定文本,返回true,否则返回false。

let t = 'abcdefg'
if(t.startsWith('ab')) {
 console.log(2)
}
//true
endsWith(str, index):如果在字符串的结束部分检测到指定文本,返回true,否则返回false。

let t = 'abcdefg'
if(t.endsWith('fg')) {
 console.log(2)
}
//true

如果你只是需要匹配字符串中是否包含某子字符串,那么推荐使用新增的方法,如果需要找到匹配字符串的位置,使用indexOf()。

三、函数

函数的默认参数

在ES5中,我们给函数传参数,然后在函数体内设置默认值,如下面这种方式。

function a(num, callback) {
 num = num || 6
 callback = callback || function (data) {console.log('ES5: ', data)}
 callback(num * num)
}
a() //ES5: 36,不传参输出默认值

//你还可以这样使用callback
a(10, function(data) {
 console.log(data * 10) // 1000, 传参输出新数值
})

在ES6中,我们使用新的默认值写法

function a(num = 6, callback = function (data) {console.log('ES6: ', data)}) {
 callback(num * num)
}

a() //ES6: 36, 不传参输出默认值

a(10, function(data) {
 console.log(data * 10) // 1000,传参输出新数值
})

四、箭头函数(=>)

(箭头函数比较重要,现在简单提一下,迟一点有空专门写一篇箭头函数的文章。)

const arr = [5, 10]
const s = arr.reduce((sum, item) => sum + item)
console.log(s) // 15

箭头函数中this的使用跟普通函数也不一样,在JavaScript的普通函数中,都会有一个自己的this值,主要分为:

普通函数:

1、函数作为全局函数被调用时,this指向全局对象
2、函数作为对象中的方法被调用时,this指向该对象
3、函数作为构造函数的时候,this指向构造函数new出来的新对象
4、还可以通过call,apply,bind改变this的指向

箭头函数:

1、箭头函数没有this,函数内部的this来自于父级最近的非箭头函数,并且不能改变this的指向。
2、箭头函数没有super
3、箭头函数没有arguments
4、箭头函数没有new.target绑定。
5、不能使用new
6、没有原型
7、不支持重复的命名参数。

箭头函数的简单理解

1、箭头函数的左边表示输入的参数,右边表示输出的结果。

const s = a => a
console.log(s(2)) // 2

2、在箭头函数中,this属于词法作用域,直接由上下文确定,对于普通函数中指向不定的this,箭头函数中处理this无疑更加简单,如下:

//ES5普通函数
function Man(){
 this.age=22;
 return function(){
 this.age+1;
 }
}
var cala=new Man();
console.log(cala())//undefined
//ES6箭头函数
function Man(){
 this.age=22;
 return () => this.age+1;
}
var cala=new Man();
console.log(cala())//23

3、箭头函数中没有arguments(我们可以用rest参数替代),也没有原型,也不能使用new 关键字,例如:

//没有arguments
var foo=(a,b)=>{return arguments[0]*arguments[1]}
console.log(foo(3,5))
//arguments is not defined
//没有原型
var Obj = () => {};
console.log(Obj.prototype); 
// undefined
//不能使用new 关键字
var Obj = () => {"hello world"};
var o = new Obj(); 
// TypeError: Obj is not a constructor

4、箭头函数给数组排序

const arr = [10, 50, 30, 40, 20]
const s = arr.sort((a, b) => a - b)
console.log(s) // [10,20,30,40,50]

尾调用优化

尾调用是指在函数return的时候调用一个新的函数,由于尾调用的实现需要存储到内存中,在一个循环体中,如果存在函数的尾调用,你的内存可能爆满或溢出。

ES6中,引擎会帮你做好尾调用的优化工作,你不需要自己优化,但需要满足下面3个要求:

1、函数不是闭包
2、尾调用是函数最后一条语句
3、尾调用结果作为函数返回

尾调用实际用途——递归函数优化
在ES5时代,我们不推荐使用递归,因为递归会影响性能。
但是有了尾调用优化之后,递归函数的性能有了提升。

//新型尾优化写法
"use strict"; 
function a(n, p = 1) {
 if(n <= 1) {
 return 1 * p
 }
 let s = n * p
 return a(n - 1, s)
}
//求 1 x 2 x 3的阶乘
let sum = a(3)
console.log(sum) // 6

五、ES6对象新增方法

Object.assign()

Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()和Object.defineProperty() 。

String类型和 Symbol 类型的属性都会被拷贝。

合并对象

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

合并具有相同属性的对象

var o1 = { a: 1, b: 1, c: 1 };
var o2 = { b: 2, c: 2 };
var o3 = { c: 3 };
var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

六、Map和Set

Map和Set都叫做集合,但是他们也有所不同。Set常被用来检查对象中是否存在某个键名,Map集合常被用来获取已存的信息。
Set是有序列表,含有相互独立的非重复值。
Array和Set对比
都是一个存储多值的容器,两者可以互相转换,但是在使用场景上有区别。如下:
Array的indexOf方法比Set的has方法效率低下
Set不含有重复值(可以利用这个特性实现对一个数组的去重)
Set通过delete方法删除某个值,而Array只能通过splice。两者的使用方便程度前者更优
Array的很多新方法map、filter、some、every等是Set没有的(但是通过两者可以互相转换来使用)
Object和Map对比
Object是字符串-值,Map是值-值
Object键为string类型,Map的键是任意类型
手动计算Object尺寸,Map.size可以获取尺寸

Map的排序是插入顺序

Object有原型,所以映射中有一些缺省的键。可以理解为Map=Object.create(null)

Set操作集合

let set = new Set()
// Set转化为数组
let arr = Array.from(set)
let arr = [...set]
// 实例属性(继承自Set)
set.constructor === Set 
set.size 
// 操作方法
set.add(1) // 添加一个值
set.delete(1) //删除一个值
set.has(1) //判断是否有这个值(Array中的indexOf)
set.clear() //清除所有值
// 获取用于遍历的成员方法(Set的遍历顺序就是插入顺序)
set.keys() // 返回键名的遍历器
set.values() // 返回键值得遍历器
set.entries() // 返回键值对的遍历器
set.forEach() // 循环遍历每个值(和Array的方法一致)
for (let key of set.keys()){}
for (let val of set.values()){}
for (let entry of set.entries()){}
// 使用数组方法来处理set值
set = new Set(arr)
set = new Set([...set].map((x) => x = x * 2))
set = new Set([...set].filter((x) => x > 2))

Map的方法集合

let map = new Map()
// 实例属性(继承自Map)
map.constructor === Map
map.size
// 操作方法
map.set(1,2)
map.get(1)
map.delete(1)
map.has(1)
map.clear()
// 遍历方法
map.keys()
map.values()
map.entries()
map.forEach()
// Map和数组的转换
map = new Map([['key','val'],[2,1]]) // 要求双成员数组
let arr = [...map]
// 值得注意的是Map的键是跟内存绑定的
map.set([1], 's')
map.get([1])
let arr = [1]
let arr1 = [1]
map.set(arr, 's')
map.get(arr)
map.set(arr1, 's')
map.get(arr1)

七、迭代器(Iterator)

1、entries() 返回迭代器:返回键值对

//数组
const arr = ['a', 'b', 'c'];
for(let v of arr.entries()) {
 console.log(v)
}
// [0, 'a'] [1, 'b'] [2, 'c']
//Set
const arr = new Set(['a', 'b', 'c']);
for(let v of arr.entries()) {
 console.log(v)
}
// ['a', 'a'] ['b', 'b'] ['c', 'c']
//Map
const arr = new Map();
arr.set('a', 'a');
arr.set('b', 'b');
for(let v of arr.entries()) {
 console.log(v)
}
// ['a', 'a'] ['b', 'b']

2、values() 返回迭代器:返回键值对的value

//数组
const arr = ['a', 'b', 'c'];
for(let v of arr.values()) {
 console.log(v)
}
//'a' 'b' 'c'
//Set
const arr = new Set(['a', 'b', 'c']);
for(let v of arr.values()) {
 console.log(v)
}
// 'a' 'b' 'c'
//Map
const arr = new Map();
arr.set('a', 'a');
arr.set('b', 'b');
for(let v of arr.values()) {
 console.log(v)
}
// 'a' 'b'

3、keys() 返回迭代器:返回键值对的key

//数组
const arr = ['a', 'b', 'c'];
for(let v of arr.keys()) {
 console.log(v)
}
// 0 1 2
//Set
const arr = new Set(['a', 'b', 'c']);
for(let v of arr.keys()) {
 console.log(v)
}
// 'a' 'b' 'c'
//Map
const arr = new Map();
arr.set('a', 'a');
arr.set('b', 'b');
for(let v of arr.keys()) {
 console.log(v)
}
// 'a' 'b'

虽然上面列举了3种内建的迭代器方法,但是不同集合的类型还有自己默认的迭代器,在for of中,数组和Set的默认迭代器是values(),Map的默认迭代器是entries()。

for of循环解构

对象本身不支持迭代,但是我们可以自己添加一个生成器,返回一个key,value的迭代器,然后使用for of循环解构key和value。

const obj = {
 a: 1,
 b: 2,
 *[Symbol.iterator]() {
 for(let i in obj) {
  yield [i, obj[i]]
 }
 }
}
for(let [key, value] of obj) {
 console.log(key, value)
}
// 'a' 1, 'b' 2

字符串迭代器

const str = 'abc';
for(let v of str) {
 console.log(v)
}
// 'a' 'b' 'c'

ES6给数组添加了几个新方法:find()、findIndex()、fill()、copyWithin()

1、find():传入一个回调函数,找到数组中符合当前搜索规则的第一个元素,返回它,并且终止搜索。

const arr = [1, "2", 3, 3, "2"]
console.log(arr.find(n => typeof n === "number")) // 1

2、findIndex():传入一个回调函数,找到数组中符合当前搜索规则的第一个元素,返回它的下标,终止搜索。

const arr = [1, "2", 3, 3, "2"]
console.log(arr.findIndex(n => typeof n === "number")) // 0

3、fill():用新元素替换掉数组内的元素,可以指定替换下标范围。

arr.fill(value, start, end)

4、copyWithin():选择数组的某个下标,从该位置开始复制数组元素,默认从0开始复制。也可以指定要复制的元素范围。

arr.copyWithin(target, start, end)
const arr = [1, 2, 3, 4, 5]
console.log(arr.copyWithin(3)) // [1,2,3,1,2] 从下标为3的元素开始,复制数组,所以4, 5被替换成1, 2
const arr1 = [1, 2, 3, 4, 5]
console.log(arr1.copyWithin(3, 1)) // [1,2,3,2,3] 从下标为3的元素开始,复制数组,指定复制的第一个元素下标为1,所以4, 5被替换成2, 3
const arr2 = [1, 2, 3, 4, 5]
console.log(arr2.copyWithin(3, 1, 2)) // [1,2,3,2,5] 从下标为3的元素开始,复制数组,指定复制的第一个元素下标为1,结束位置为2,所以4被替换成2

ES6中类class、Promise与异步编程、代理(Proxy)和反射(Reflection)API,这几块内容比较复杂,以后有机会再详细写。

总结

以上所述是小编给大家介绍的工作中常用到的ES6语法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
不使用中间变量,交换int型的 a, b两个变量的值。
Oct 29 Javascript
js鼠标滑过弹出层的定位IE6bug解决办法
Dec 26 Javascript
动态加载script文件的两种方法
Aug 15 Javascript
使用js判断当前时区TimeZone是否是夏令时
Feb 23 Javascript
IE下通过a实现location.href 获取referer的值
Sep 04 Javascript
node.js中的fs.futimesSync方法使用说明
Dec 17 Javascript
JavaScript限定图片显示大小的方法
Mar 11 Javascript
HTML5canvas 绘制一个圆环形的进度表示实例
Dec 16 Javascript
微信小程序 数组(增,删,改,查)等操作实例详解
Jan 05 Javascript
详解在AngularJS的controller外部直接获取$scope
Jun 02 Javascript
create-react-app构建项目慢的解决方法
Mar 14 Javascript
ajax与jsonp的区别及用法
Oct 16 Javascript
用POSTMAN发送JSON格式的POST请求示例
Sep 04 #Javascript
JS实现可针对算术表达式求值的计算器功能示例
Sep 04 #Javascript
解决vue 打包发布去#和页面空白的问题
Sep 04 #Javascript
详解JS中统计函数执行次数与执行时间
Sep 04 #Javascript
Vue组件中的data必须是一个function的原因浅析
Sep 03 #Javascript
ES6中let 和 const 的新特性
Sep 03 #Javascript
Angular项目如何升级至Angular6步骤全纪录
Sep 03 #Javascript
You might like
Smarty模板快速入门
2007/01/04 PHP
php对包含html标签的字符串进行截取的函数分享
2014/06/19 PHP
php+mysqli实现批量替换数据库表前缀的方法
2014/12/29 PHP
JS操作Cookie写入和读取实例代码
2013/10/20 Javascript
理解Javascript的动态语言特性
2015/06/17 Javascript
jquery对Json的各种遍历方法总结(必看篇)
2016/09/29 Javascript
Boostrap实现的登录界面实例代码
2016/10/09 Javascript
Angular1.x复杂指令实例详解
2017/03/01 Javascript
NodeJS实现微信公众号关注后自动回复功能
2017/05/31 NodeJs
vue-cli单页应用改成多页应用配置详解
2017/07/14 Javascript
[js高手之路]单例模式实现模态框的示例
2017/09/01 Javascript
jQuery实现获取动态添加的标签对象示例
2018/06/28 jQuery
vue动态设置img的src路径实例
2018/09/18 Javascript
JS/HTML5游戏常用算法之碰撞检测 像素检测算法实例详解
2018/12/12 Javascript
配置node服务器并且链接微信公众号接口配置步骤详解
2019/06/21 Javascript
javascript中的this作用域详解
2019/07/15 Javascript
vue + elementUI实现省市县三级联动的方法示例
2019/10/29 Javascript
javascript设计模式 ? 组合模式原理与应用实例分析
2020/04/14 Javascript
jQuery实现朋友圈查看图片
2020/09/11 jQuery
js获取图片的base64编码并压缩
2020/12/05 Javascript
用python的requests第三方模块抓取王者荣耀所有英雄的皮肤实例
2017/12/14 Python
Python+matplotlib+numpy绘制精美的条形统计图
2018/01/02 Python
python的socket编程入门
2018/01/29 Python
使用django的ORM框架按月统计近一年内的数据方法
2019/07/18 Python
python 导入数据及作图的实现
2019/12/03 Python
python模拟预测一下新型冠状病毒肺炎的数据
2020/02/01 Python
Django 项目通过加载不同env文件来区分不同环境
2020/02/17 Python
浅谈python输出列表元素的所有排列形式
2020/02/26 Python
Python decorator拦截器代码实例解析
2020/04/04 Python
python3+openCV 获取图片中文本区域的最小外接矩形实例
2020/06/02 Python
Python爬虫入门教程02之笔趣阁小说爬取
2021/01/24 Python
工商管理专业实习大学生自我鉴定
2013/09/19 职场文书
社会实践先进工作者事迹材料
2014/05/06 职场文书
在宿舍喝酒的检讨书
2014/09/28 职场文书
个人四风问题整改措施思想汇报
2014/10/04 职场文书
Python+OpenCV实现在图像上绘制矩形
2022/03/21 Python