网上杂七杂八的ES6语法看的眼花缭乱,今天没事自己总结下一些常用的,加深下印象。
ES6是什么东东呢,其实就是JavaScript的下一代标准。全称ECMAScrpt 6.0。大家常说的ES2015其实就是ES6的第一个版本。其实不必纠结这些。它们俩没啥区别,都指下一代JS标准。
下面列举下常见的新功能。
1. let和const
这个算是高频使用的了,ES6里代替var,let定义变量,const定义常量。
- let
跟ES5相比,有两点不同.
一是不存在变量提升:
console.log(a) // undefined
console.log(b) // 报错:b未定义
var a = 1
let b = 1
因为let不存在变量提升,所以会有所谓的暂时性死区(这个区块中变量未声明之前,对该变量的一切调用都会报错)。其实ES6这样设计的目的就是为了让我们养成规范的代码习惯,先声明再调用。这一点一定要注意。
二是let声明的变量不能重复声明,否则会报错
var i = 1;
var i = 2;
console.log(i)//2
let i = 1;
let i = 2;
console.log(i)//报错
当然在不同的区块内重复声明就可以,比如for循环其实就是2个区块,()的可以理解为父作用域,{}里的为子作用域。
for(let i = 0; i < 5; i++){
let i = 7;
console.log(i)
}
// 输出结果是5个7
这里没有报错,说明()和{}其实是2个作用域。
三是新增了块级作用域。
for(var i = 0; i < 5; i++){
}
console.log(i) // 5
for(let i = 0; i < 5; i++){ // 这个i只能在这个for循环内使用
}
console.log(i) // 报错:i is not defined
一个常见的闭包问题就可以用let来解决。
for(var i = 0; i < 5; i++){
setTimeout(function(){
console.log(i)
}, 1000)
}
这个可谓是经典的闭包题了,结果是一次性输出5个5。如何让它输出01234呢,ES5我们用IIFE来解决。
for(var i = 0; i < 5; i++){
(function(e){
setTimeout(function(){
console.log(e)
}, 1000)
})(i)
}
将代码放在一个IIFE中创建了一个独立的作用域,传入i,这样就实现了对i的暂存。(详细可参看我的另一篇关于闭包的文章。)
ES6就可以用let来解决了。
for(let i = 0; i < 5; i++){
setTimeout(function(){
console.log(i)
}, 1000)
}
其实JS引擎解析上述代码中的let,就是按照ES5的规范来解析的。即创建一个IIFE传入i.
- const
1.声明的时候就要初始化,否则会报错
const a ;//报错
2.声明的值不能改变,不能重复声明,不存在变量提升。
const a = 1;
let a = 2//报错
var a = 2//报错
a = 2//报错
想到的就这么多,随时补充。
2. 箭头函数
这尼玛是巅峰了js的编码习惯,一点都不适应好嘛!!还是超喜欢以前笨笨的写法。。
废话不多说,用法如下:
var fn = function(a, b) {
return a + b;
}//es5
var fn = (a, b) => a + b//es6
总结下几种情况下的写法:
() => { … } // 零个参数用 () 表示
x => { … } // 一个参数可以省略 ()
(x, y) => { … } // 多参数不能省略 ()
箭头函数最直观的特点就是:不需要function关键字创建函数,省略return关键字,继承上下文的this关键字。
重点来了!重点来了!这里着重说一下this,这个可谓是箭头函数里最重要的也是面试中最容易考察的问题。
我们都知道在普通函数里。this的使用情况如下:
- this指代它的直接调用者。比如a.fn()。fn()里的this指向a。
- 使用call,apply,bind时,this指向绑定的对象。a.call(b,..) this指向b。比如:
var sayName = function () {
console.log(this.name);
}
var peter = {
name: "peter"
}
sayName.call(peter);//peter
使用了call,this就指向了peter,peter继承了sayName方法。this.name即为peter.name。
- 非严格模式下,没直接调用者,this即指向window。
- 严格模式下('use strict'),没直接调用者,this是undefind。
那么在箭头函数中。它没有自己的this,它的this继承而来,即定义时所在的上下文的this。
普通函数中:
var x=11;
var obj={
x:22,
say:function() {
console.log(this.x)
}
}
obj.say();//22 this指向obj
箭头函数中:
var x=11;
var obj={
x:22,
say:()=>{
console.log(this.x);
}
}
obj.say();//11 this指向window
此时this在obj内定义的,指代window。
3. 模板字符串
模板字符串就是为了解决使用+拼接字符串的不便利而出现的。它有三个用法
- 多行文本
var str = '<html>'
+ '<div>啦拉拉</div>'
+ '<div>xixixi</div>'
+ '</html>';
console.log(str);// <html><div>啦拉拉</div><div>xixixi</div></html>
ES6中就可以这样写
let str = `<html>
<div>啦拉拉</div>
<div>xixixix</div>
</html>`;
console.log(str);
- 插入变量或表达式
可在${}中插入变量或表达式。
ES5中用+来拼接字符串。
var name = 'sean';
var age = 26;
var info = 'my name is ' + name + ',age is ' + age;
console.log(info)//my name is sean,age is 26
ES6中就可以这样写
let name = 'sean';
let age = 26;
let info = `my name is ${name},age is ${age},like ${age+1}`;
console.log(info)//my name is sean,age is 26,like 27
很方便的样子哦。刚开始是有点别扭,多用用就熟练了。
4. 解析结构
所谓解构就是ES6中新增的功能,它可以从数组或对象中取出数据保存为变量。
ES5中我们是这样提取信息的:
const people = {
name: 'sean',
age: 20
}
const name = people.name
const age = people.age
console.log(name + ' --- ' + age)
ES6中这样使用:
//对象
const people = {
name: 'sean',
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'
5. 函数的默认参数
ES5中是这样定义函数的默认参数的
function action(num) {
num = num || 200
//当传入num时,num为传入的值
//当没传入参数时,num即有了默认值200
return num
}
ES6为参数提供了默认值。在定义函数时便初始化了这个参数,以便在参数没有被传递进去时使用。
function action(num = 200) {
console.log(num)
}
action(0) // 0
action() //200
action(300) //300
6. 展开运算符
可以用来组装数组或者对象
//数组
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"
}
7. import和export
历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的require、Python 的import,甚至就连 CSS 都有@import,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
使用export命令定义了模块的对外接口,其他 JS 文件就可以通过import命令加载这个模块。
8. 对象字面量 和 类(class)
其实这两个都是为了使代码更加简洁清晰。
- 对象字面量简写
在对象中,如果属性和值同名时,可以这样写:
// es6
const person = {
name,
age,
getName() { // 只要不使用箭头函数,this就还是我们熟悉的this
return this.name
}
}
// es5
var person = {
name: name,
age: age,
getName: function getName() {
return this.name;
}
};
- class
ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
// ES5
// 构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 原型方法
Person.prototype.getName = function() {
return this.name
}
// ES6
class Person {
constructor(name, age) { // 构造函数
this.name = name;
this.age = age;
}
getName() { // 原型方法
return this.name
}
}
是不是很简单明了。
9. Promise
在promise之前代码过多的回调或者嵌套,可读性差、耦合度高、扩展性低。通过Promise机制,扁平化的代码机构,大大提高了代码可读性;用同步编程的方式来编写异步代码,保存线性的代码逻辑,极大的降低了代码耦合性而提高了程序的可扩展性。
其实就是用同步的方式去写异步代码。
下面代码创造了一个Promise实例
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。resolve即成功时调用,resolve失败时调用。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
随时补充。。
相关链接: