es6中有很多特征,使javascript语法越发饱满,总结一波经常运用的es6知识点。
1.变量声明const和let
在ES6之前,我们都是用var关键字声明变量。不管声明在那边,都邑被视为声明在函数的最顶部(不在函数内即在全局作用域的最顶部)。这就是函数变量提拔比方:
function a() {
if(bool) {
var str // 变量提拔
str = 'frontend'
} else {
//此处接见str 值为undefined
console.log(str)
}
}
所以没必要体贴bool是不是为true or false。现实上,不管怎样str都邑被竖立声明。
而es6以后,我们通经常运用let和const来声明。let示意变量、const示意常量,let和const都是块级作用域。怎样明白这个块级作用域?
- 在一个函数内部
- 在一个代码块内部
平常来讲{}大括号内的代码块即为let 和 const的作用域。
function a() {
if(bool) {
let str = 'frontend
} else {
//str 在此处接见不到
console.log(str)
}
}
let 的作用域是在它所在当前代码块,但不会被提拔到当前函数的最顶部。
const 声明的变量都邑被认为是常量,示意它的值被设置完成后就不能再修正了。
const role = 'frontend'
role = 'backend' //再次赋值此时会报错
假如const的是一个对象,对象所包括的值是可以被修正的。就是对象所指向的地点没有变就行。
const student = { name: 'cc' }
// 不报错
student.name = 'yy'
// 假如这模样就会报错了
student = { name: 'yy' }
罕见口试题中:
var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push(function() { console.log(i) })
}
funcs.forEach(function(func) {
func()
})
如许的口试题是人人罕见,很多同砚一看就晓得输出 10 十次
然则假如我们想顺次输出0到9呢?
有两种处置惩罚要领。直接看一下代码。
// ES5应用闭包处置惩罚这个题目
var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push(
(function(value) {
return function() {
console.log(value)
}
})(i)
)
}
funcs.forEach(function(func) {
func()
})
// es6处置惩罚
const funcs = []
for (let i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i)
})
}
funcs.forEach(func => func())
es6处置惩罚计划越发简约轻易。
2.模板字符串
es6模板字符简直是开发者的福音,处置惩罚了es5在字符串功用上的痛点。
第一个用途,基础的字符串格式化。将表达式嵌入字符串中举行拼接。用${}来界定。
//ES5
var name = 'frontend'
console.log('hello' + name)
//es6
const name = 'frontend'
console.log(`hello ${name}`)
第二个用途,在ES5时我们经由历程反斜杠()来做多行字符串也许字符串一行行拼接。ES6反引号(“)直接搞定。
// ES5
var msg = "Hi \
man!
"
// ES6
const template = `<div>
<span>hello world</span>
</div>`
关于字符串ES6固然也供应了很多凶猛也很有意义的要领。
// 1.includes:推断是不是包括然后直接返回布尔值
const str = 'hahay'
console.log(str.includes('y')) // true
// 2.repeat: 猎取字符串反复n次
const str = 'he'
console.log(str.repeat(3)) // 'hehehe'
//假如你带入小数, Math.floor(num) 来处置惩罚
// s.repeat(3.1) 也许 s.repeat(3.9) 都当做成 s.repeat(3) 来处置惩罚
// 3. startsWith 和 endsWith 推断是不是以 给定文本 最先也许完毕
const str = 'hello world!'
console.log(str.startsWith('hello')) // true
console.log(str.endsWith('!')) // true
3.函数
函数默许参数
在ES5我们给函数定义参数默许值是怎样?
function action(num) {
num = num || 200
//当传入num时,num为传入的值
//当没传入参数时,num即有了默许值200
return num
}
但仔细视察的同砚们肯定会发明,num传入为0的时刻就是false,然则我们现实的需求就是要拿到num = 0,此时num = 200 显著与我们的现实想要的结果显著不一样。
ES6为参数供应了默许值。在定义函数时便初始化了这个参数,以便在参数没有被通报进去时运用。
function action(num = 200) {
console.log(num)
}
action(0) // 0
action() //200
action(300) //300
箭头函数
ES6很有意义的一部份就是函数的快速写法。也就是箭头函数。
箭头函数最直观的三个特性。
- 不须要 function 关键字来竖立函数
- 省略 return 关键字
- 继承当前上下文的 this 关键字
//比方:
[1,2,3].map(x => x + 1)
//等同于:
[1,2,3].map((function(x){
return x + 1
}).bind(this))
说个小细节。
当你的函数有且唯一一个参数的时刻,是可以省略掉括号的。当你函数返回有且唯一一个表达式的时刻可以省略{} 和 return;比方:
var people = name => 'hello' + name
//参数name就没有括号
作为参考
var people = (name, age) => {
const fullName = 'hello' + name
return fullName
}
//假如缺乏()也许{}就会报错
来道笔试题:
// 请运用ES6重构以下代码
var calculate = function(x, y, z) {
if (typeof x != 'number') { x = 0 }
if (typeof y != 'number') { y = 6 }
var dwt = x % y
var result
if (dwt == z) { result = true }
if (dwt != z) { result = false }
return result
}
const calculate = (x, y, z) => {
x = typeof x !== 'number' ? 0 : x
y = typeof y !== 'number' ? 6 : y
return x % y === z
}
4.拓展的对象功用
对象初始化简写
ES5我们关于对象都是以键值对的情势誊写,是有可以涌现键值对重名的。比方:
function people(name, age) {
return {
name: name,
age: age
};
}
键值对重名,ES6可以简写以下:
function people(name, age) {
return {
name,
age
};
}
ES6 一样革新了为对象字面量要领赋值的语法。ES5为对象增加要领:
const people = {
name: 'sa',
getName: function() {
console.log(this.name)
}
}
ES6经由历程省略冒号与 function 关键字,将这个语法变得更简约
const people = {
name: 'sa',
getName () {
console.log(this.name)
}
}
ES6 对象供应了 Object.assign() 这个要领来完成浅复制。
Object.assign() 可以把恣意多个源对象本身可罗列的属性拷贝给目的对象,然后返回目的对象。第一参数即为目的对象。在现实项目中,我们为了不转变源对象。平常会把目的对象传为{}
const objA = { name: 'cc', age: 18 }
const objB = { address: 'beijing' }
const objC = {} // 这个为目的对象
const obj = Object.assign(objC, objA, objB)
// 我们将 objA objB objC obj 离别输出看看
console.log(objA) // { name: 'cc', age: 18 }
console.log(objB) // { address: 'beijing' }
console.log(objC) // { name: 'cc', age: 18, address: 'beijing' }
console.log(obj) // { name: 'cc', age: 18, address: 'beijing' }
// 是的,目的对象ObjC的值被转变了。
// so,假如objC也是你的一个源对象的话。请在objC前面填在一个目的对象{}
Object.assign({}, objC, objA, objB)
5.更轻易的数据接见–解构
数组和对象是JS中最经常运用也是最主要示意情势。为了简化提取信息,ES6新增了解构,这是将一个数据结构分解为更小的部份的历程
ES5我们提取对象中的信息情势以下:
const people = {
name: 'lux',
age: 20
}
const name = people.name
const age = people.age
console.log(name + ' --- ' + age)
是不是是以为很熟悉,没错,在ES6之前我们就是如许猎取对象信息的,一个一个猎取。如今,解构能让我们从对象也许数组里掏出数据存为变量,比方
//对象
const people = {
name: 'sa',
age: 20
}
const { name, age } = people
console.log(`${name} --- ${age}`)
//数组
const color = ['red', 'blue']
const [first, second] = color
console.log(first) //'red'
console.log(second) //'blue'
口试题:
// 请运用 ES6 重构一下代码
// 第一题
var jsonParse = require('body-parser').jsonParse
// 第二题
var body = request.body
var username = body.username
var password = body.password
// 1.
import { jsonParse } from 'body-parser'
// 2.
const { body, body: { username, password } } = request
6.Spread Operator 睁开运算符
ES6中别的一个好玩的特征就是Spread Operator 也是三个点儿…接下来就展现一下它的用途。
组装对象也许数组
//数组
const color = ['red', 'yellow']
const colorful = [...color, 'green', 'pink']
console.log(colorful) //[red, yellow, green, pink]
//对象
const alp = { fist: 'a', second: 'b'}
const alphabets = { ...alp, third: 'c' }
console.log(alphabets) //{ "fist": "a", "second": "b", "third": "c" }
有时刻我们想猎取数组也许对象除了前几项也许除了某几项的其他项
//数组
const number = [1,2,3,4,5]
const [first, ...rest] = number
console.log(rest) //2,3,4,5
//对象
const user = {
username: 'lux',
gender: 'female',
age: 19,
address: 'peking'
}
const { username, ...rest } = user
console.log(rest) //{"address": "peking", "age": 19, "gender": "female" }
关于 Object 而言,还可以用于组合成新的 Object 。(ES2017 stage-2 proposal) 固然假如有反复的属性名,右侧掩盖左侧
const first = {
a: 1,
b: 2,
c: 6,
}
const second = {
c: 3,
d: 4
}
const total = { ...first, ...second }
console.log(total) // { a: 1, b: 2, c: 3, d: 4 }
7.import 和 export
import导入模块、export导出模块
//悉数导入
import people from './example'
//有一种特殊情况,即许可你将全部模块看成单一对象举行导入
//该模块的一切导出都邑作为对象的属性存在
import * as example from "./example.js"
console.log(example.name)
console.log(example.age)
console.log(example.getName())
//导入部份
import {name, age} from './example'
// 导出默许, 有且只要一个默许
export default App
// 部份导出
export class App extend Component {};
导入的时刻有无大括号的区分是什么。下面是总结:
1.当用export default people导出时,就用 import people 导入(不带大括号)
2.一个文件里,有且只能有一个export default。但可以有多个export。
3.当用export name 时,就用import { name }导入(记得带上大括号)
4.当一个文件里,既有一个export default people, 又有多个export name 也许 export age时,导入就用 import people, { name, age }
5.当一个文件里涌现n多个 export 导出很多模块,导入时除了一个一个导入,也可以用import * as example
8. Promise
在promise之前代码过量的回调也许嵌套,可读性差、耦合度高、扩展性低。经由历程Promise机制,扁平化的代码机构,大大提高了代码可读性;用同步编程的体式格局来编写异步代码,保留线性的代码逻辑,极大的降低了代码耦合性而提高了顺序的可扩展性。
说白了就是用同步的体式格局去写异步代码。
提议异步要求:
fetch('/api/todos')
.then(res => res.json())
.then(data => ({ data }))
.catch(err => ({ err }));
口试题:
setTimeout(function() {
console.log(1)
}, 0);
new Promise(function executor(resolve) {
console.log(2);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
9.Generators
天生器( generator)是能返回一个迭代器的函数。天生器函数也是一种函数,最直观的表现就是比一般的function多了个星号*,在其函数体内可以运用yield关键字,有意义的是函数会在每一个yield后停息。
这里生涯中有一个比较抽象的例子。我们到银行解决营业时刻都得向大厅的机械取一张列队号。你拿到你的列队号,机械并不会自动为你再出下一张票。也就是说取票机“停息”住了,直到下一个人再次唤起才会继承吐票。
OK。说说迭代器。当你挪用一个generator时,它将返回一个迭代器对象。这个迭代器对象具有一个叫做next的要领来协助你重启generator函数并取得下一个值。next要领不仅返回值,它返回的对象具有两个属性:done和value。value是你取得的值,done用来表明你的generator是不是已住手供应值。继承用刚刚取票的例子,每张列队号就是这里的value,打印票的纸是不是用完就这是这里的done。
// 天生器
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// 天生器能像正规函数那样被挪用,但会返回一个迭代器
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
那天生器和迭代器又有什么用途呢?
围绕着天生器的很多兴奋点都与异步编程直接相干。异步挪用关于我们来讲是很难题的事,我们的函数并不会守候异步挪用完再实行,你可以会想到用回调函数,(固然另有其他计划比方Promise比方Async/await)。
天生器可以让我们的代码举行守候。就没必要嵌套的回调函数。运用generator可以确保当异步挪用在我们的generator函数运转一下行代码之前完成时停息函数的实行。
那末题目来了,我们也不能手动一向挪用next()要领,你须要一个可以挪用天生器并启动迭代器的要领。就像这模样的
function run(taskDef) { //taskDef即一个天生器函数
// 竖立迭代器,让它在别处可用
let task = taskDef();
// 启动使命
let result = task.next();
// 递归运用函数来坚持对 next() 的挪用
function step() {
// 假如另有更多要做的
if (!result.done) {
result = task.next();
step();
}
}
// 最先处置惩罚历程
step();
}
天生器与迭代器最风趣、最令人激动的方面,也许就是可竖立表面清楚的异步操纵代码。你没必要随处运用回调函数,而是可以竖立貌似同步的代码,但现实上却运用 yield 来守候异步操纵完毕。
10.async 函数
es6引入了 async 函数,使得异步操纵变得越发轻易。
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
一比较就会发明,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此罢了。
async函数对 Generator 函数的革新,体如今以下四点。
- 内置实行器
- 更好的语义
- 更广的适用性
- 返回值是 Promise
11.Class基础语法
JavaScript 言语中,天生实例对象的传统要领是经由历程组织函数
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关键字,可以定义类。
基础上,es6 的%(red)[class]可以看做只是一个语法糖,它的绝大部份功用,es5 都可以做到,新的%(red)[class]写法只是让对象原型的写法越发清楚、更像面向对象编程的语法罢了。上面的代码用 es6 的%(red)[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这个关键字,直接把函数定义放进去了就可以了。别的,要领之间不须要逗号分开,加了会报错。
es6 的类,完全可以看做组织函数的另一种写法。