我理解的ES6
前言
我是通过阮一峰老师的ES6教程入门的,基本上是把ES6的几个核心特性过了一遍,但是面试官一问深我就???了,还是实际运用的太少。
工具:Babel是一个 ES6 转码器,可以将 ES6 代码转为 ES5 代码,以便兼容那些还没支持ES6的平台。
String字符串优化
新增了字符串模板,在拼接大段字符串时,用反斜杠取代以往的字符串相加的形式,能保留所有空格和换行,使得字符串拼接看起来更加直观,更加优雅。
新增了includes()方法,用于取代传统的只能用indexOf查找包含字符的方法, 此外还新增了startsWith(), endsWith(), padStart(),padEnd(),repeat()等方法,可方便的用于查找,补全字符串。
Array数组优化
数组解构赋值: 如ES6可以直接以let [a,b,c] = [1,2,3]
形式进行变量赋值,映射关系更清晰。
扩展运算符:
- 可以将一个数组转为用逗号分隔的参数序列。
console.log(...[1, 2, 3]) // 1 2 3
-
可以实现数组的复制和解构赋值
(let a = [2,3,4]; let b = [...a])
-
可以取代arguments对象和apply方法,轻松获取未知参数个数情况下的参数集合。
使用扩展运算符替代函数的apply方法:
// ES5 的写法
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f.apply(null, args);
// ES6 写法
let args = [0, 1, 2];
f(...args);
JS中遍历数组的方法:
- for循环
- forEach
myArray.forEach(function(value){
console.log(value);
})
无法中途跳出forEach循环,break命令或return命令都不能奏效。
for... in
for…in主要是为遍历对象而设计的,不适用于遍历数组。
遍历数组的缺点:
- 数组的键名是数字,但是for…in循环是以字符串作为键名的。
- 某些情况下,for…in循环会以任意顺序遍历键名。
for...of
(ES6)
for(let value of myArray){
console.log(value);
}
- 不同用于forEach方法,它可以与break、continue和return配合使用。
- 提供了遍历所有数据结构的统一操作接口。
for of 和 for in 的总结:
- 推荐在循环对象属性的时候,使用for...in, 在遍历数组的时候的时候使用for...of。
- for...in循环出的是key,for...of循环出的是value
- 注意,for...of是ES6新引入的特性。修复了ES5引入的for...in的不足
- for...of不能循环普通的对象,需要通过和Object.keys()搭配使用
Object类型优化
- 对象属性变量式声明:
ES6可以直接以变量形式声明对象属性或者方法。比传统的键值对形式声明更加简洁,更加方便,语义更加清晰。
let [apple, orange] = ['red appe', 'yellow orange'];
let myFruits = {apple, orange};
// let myFruits = {apple: 'red appe', orange: 'yellow orange'};
- 对象的扩展运算符(...)
可将一个数组转为用逗号分隔的参数序列,主要用于函数调用。 console.log(...[1, 2, 3]) // 1 2 3
- super 关键字:
ES6在Class类里新增了类似this的关键字super。同this总是指向当前函数所在的对象不同,super关键字总是指向当前函数所在对象的原型对象。
箭头函数
基本使用:
如果 return 值就只有一行表达式,可以省去 return,默认表示该行是返回值,否则需要加一个大括号和 return。如果参数只有一个,也可以省去括号,两个则需要加上括号。
var f = v => v*2;
// 等价于
var f = function(v){
return v*2;
}
// 判断偶数
var isEven = n => n % 2 == 0;
// 需要加 return
var = (a, b) => {
if(a >= b)
return a;
return b;
}
ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。
rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
//利用 rest 参数,可以向该函数传入任意数目的参数。
function add(...values) {
let sum = 0;
for (var val of values) {
sum = val;
}
return sum;
}
add(2, 5, 3) // 10
面试问题:箭头函数和普通函数的区别
- 箭头函数没有自己的this对象
函数中的 this 始终是指向函数执行时所在的对象。比如全局函数执行时,this 指向 window,对象的方法执行时,this 指向该对象,这就是函数 this 的可变。
而箭头函数中的 this 是固定的,箭头函数继承自己作用域的上一层的this,就是上一级外部函数的 this 的指向。任何方法都改变不了其指向,如call(), bind(), apply()。
一个例子:
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 }); // id: 42
执行的结果是 42 而不是全局的 21,表示 setTimeout 函数执行的时候,this 指向的不是 window。因此箭头函数很好地解决了匿名函数和setTimeout
和setInterval
的this指向问题,不用再去给其用that变量存储this。
对箭头函数中关于 this 的总结:在对象的方法中直接使用箭头函数,会指向 window,其他箭头函数 this 会指向上一层的 this,箭头函数并没有存储 this。
var obj = {
id: 1,
foo: ()=>{
return this.id;
}
}
var id = 2;
obj.foo(); // 2
- 箭头函数不能当做构造函数,不能使用new,因为它没有自己的this,无法实例化。
- 箭头函数不绑定
arguments
, 取而代之用rest参数(形式为...变量名)。也没有super
、new.target
。 - 不可以使用
yield
命令,箭头函数不可用作Generator
函数。 - 箭头函数没有原型属性。
Set 和 Map
- Set
ES6引入的一种类似Array的新的数据结构,Set实例的成员类似于数组item成员,区别是Set实例的成员都是唯一,不重复的。这个特性可以轻松地实现数组去重。
Set本身是一个构造函数,用来生成 Set 数据结构。
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
console.log(i);
}
// 2 3 5 4
- Map
JavaScript 的对象(Object),本质上是键值对的集合,但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
Map
是ES6引入的一种类似Object的新的数据结构,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
const m = new Map();
const o = {p: 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"
let 和 const
没有块级作用域回来带很多难以理解的问题,比如for循环var变量泄露,变量覆盖等问题。
let
声明的变量拥有自己的块级作用域,形如for (let x...)的循环在每次迭代时都为x创建新的绑定。且修复了var声明变量带来的变量提升问题。(必须声明 'use strict' 后才能使用let声明变量,否则浏览并不能显示结果)
“变量提升”现象:即变量可以在声明之前使用,值为undefined。为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
ES5 只有全局作用域和函数作用域,没有块级作用域。
块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。
// IIFE 写法
(function () {
var tmp = ...;
...
}());
// 块级作用域写法
{
let tmp = ...;
...
}
const
声明一个只读的常量。一旦声明,常量的值就不能改变。 const 声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化。
const的作用域与let命令相同:只在声明所在的块级作用域内有效。
总结: 使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象; 使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升; 使用const声明的是常量,在后面出现的代码中不能再修改该常量的值。
Promise
主要作用是用来解决JS回调机制产生的“回调地狱”。 回调地狱带来的负面作用有以下几点:
- 代码臃肿, 可读性差, 复用性差, 容易滋生 bug。
- 耦合度过高,可维护性差。
- 只能在回调里处理异常。
Promise它不是新的语法功能,而是一种新的写法,将回调函数的嵌套,改成链式调用。
new Promise(请求1)
.then(请求2(请求结果1))
.then(请求3(请求结果2))
.catch(处理异常(异常信息))
Promise 使用总结:
- 可以通过两种方式初始化一个 Promise 对象,都会返回一个 Promise 对象。
- new Promise(fn)
- Promise.resolve(fn)
-
然后调用上一步返回的 promise 对象的 then 方法,注册回调函数。 then 中的回调函数可以有一个参数,也可以不带参数。如果 then 中的回调函数依赖上一步的返回结果,那么要带上参数。
-
最后注册 catch 异常处理函数,处理前面回调中可能抛出的异常。
简单例子:
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done');
});
}
timeout(100).then((value) => {
console.log(value);
});
timeout方法返回一个Promise实例,表示一段时间以后才会发生的结果。过了指定的时间(ms参数)以后,Promise实例的状态变为resolved,就会触发then方法绑定的回调函数。
一些常用API:
Promise.race
类方法,多个 Promise 任务同时执行,返回最先执行结束的 Promise 任务的结果,不管这个 Promise 结果是成功还是失败。
Promise.all
类方法,多个 Promise 任务同时执行。 如果全部成功执行,则以数组的方式返回所有 Promise 任务的执行结果。 如果有一个 Promise 任务 rejected,则只返回 rejected 任务的结果。
如果后续任务是异步任务的话,必须return 一个 新的 promise 对象。如果后续任务是同步任务,只需 return 一个结果即可。
new Promise(买菜)
//用买好的菜做饭
.then((买好的菜)=>{
return new Promise(做饭);
})
一个 Promise 对象有三个状态,并且状态一旦改变,便不能再被更改为其他状态:
- pending,异步任务正在进行。
- resolved (也可以叫fulfilled),异步任务执行成功。
- rejected,异步任务执行失败。
generator 以及 async/await 语法使异步处理更加接近同步代码写法,可读性更好,同时异常捕获和同步代码的书写趋于一致。
(async ()=>{
let 蔬菜 = await 买菜();
let 饭菜 = await 做饭(蔬菜);
let 送饭结果 = await 送饭(饭菜);
let 通知结果 = await 通知我(送饭结果);
})();
Generator
Generator 函数会返回一个遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
形式上,Generator 函数是一个普通函数,但是有两个特征。
- function关键字与函数名之间有一个星号;
- 函数体内部使用yield表达式,定义不同的内部状态。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }
Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是上一章介绍的遍历器对象。
下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
async和await
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
async 函数就是 Generator 函数的语法糖。
async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await。并且返回一个
Promise
,可以使用then方法添加回调函数。 当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
async函数对 Generator 函数的改进:
- 内置执行器 async函数自带执行器,不像 Generator 函数,需要调用next方法,或者用co模块,才能真正执行。
- 更好的语义
- 更好的适用性
- 返回值是 Promise 进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
例子:getJSON函数返回一个promise,这个promise成功resolve时会返回一个json对象。我们只是调用这个函数,打印返回的JSON对象,然后返回”done”。
// promise
const makeRequest = () =>
getJSON()
.then(data => {
console.log(data)
return "done"
})
makeRequest()
//使用Async/Await
const makeRequest = async () => {
console.log(await getJSON())
return "done"
}
makeRequest()
//async函数会隐式地返回一个promise,该promise的reosolve值就是函数return的值。(示例中reosolve值就是字符串”done”)
Async的优缺点:
优势: 处理 then 的调用链能够更清晰准确的写出代码。
缺点: 滥用 await 可能会导致性能问题,因为 await 会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性。
Iterator
是ES6中一个很重要概念,它并不是对象,也不是任何一种数据类型。为Set、Map、Array、Object新增一个统一的遍历API。部署了Iterator接口的对象(可遍历对象)都可以通过for...of
去遍历。
class
ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已,可以看做是构造函数的另一种写法。
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' this.x ', ' this.y ')';
};
var p = new Point(1, 2);
//ES6的class改写
class Point {
//构造方法
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' this.x ', ' this.y ')';
}
}
上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES5 的构造函数Point,对应 ES6 的Point类的构造方法。
Point类除了构造方法,还定义了一个toString方法。注意,定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。
class实现继承: Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
总结
日常前端代码开发中,有哪些值得用ES6去改进的编程优化或者规范:
- 常用箭头函数来取代
var self = this;
的做法。 - 常用let取代var命令。
- 常用数组/对象的结构赋值来命名变量,结构更清晰,语义更明确,可读性更好。
- 在长字符串多变量组合场合,用模板字符串来取代字符串累加,能取得更好地效果和阅读体验。
- 用Class类取代传统的构造函数,来生成实例化对象。
- 在大型应用开发中,要保持module模块化开发思维,分清模块之间的关系,常用import、export方法。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfjjgjj
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13