ES6(ES2015)已经发布四年了,其实平时开发中用的不少,可是有不少时候基于各类考虑仍是不能放手大胆的使用,实际上是由于对一些新特性尚未完全掌握,今天总结一下最常使用的几个特性。前端
众所周知,在JavaScript中,变量默认是全局性的,只存在函数级做用域,声明函数曾经是创造做用域的惟一方法。这点和其余编程语言存在差别,其余语言大多数都存在块级做用域。因此在ES6中,新提出的let关键字使这个缺陷获得了修复。express
if (true) {
let a = 'name';
}
console.1og (a);
// ReferenceError:a is not defined
复制代码
同时还引入的概念是const,用来定义一个常量,一旦定义之后不能够修改,不过若是是引用类型的,那么能够改变它的属性。编程
const MYNAME = 'viking';
MYNAME = 'kitty';
// "CONSTANT" is read-only
const MYNAME = ({foo: 'viking'};
MYNAME.foo = 'kitty';
//能够正常运行
复制代码
箭头函数是一种更简单的函数声明方式,能够把它看做是一种语法糖,箭头函数永远是匿名的。数组
let add = (a, b) => {
return a + b;
}
//当后面是表达式(expression)的时候,还能够简写成
let add = (a, b) => a + b;
//等同于
let add = function (a, b) {
return a + b;
}
//在回调函数中应用
let numbers = [1, 2, 3];
let doubleNumbers = numbers.map((number) => number * 2);
console.log(doubleNumbers);
//[2,4, 6]看起来很简便吧
复制代码
在工做中常常会遇到这样的问题,就是this在一个对象方法中嵌套函数。浏览器
var age = 2;
var kitty= {
age: 1,
grow: function() {
setTimeout (function() {
console.log(++this.age) ;
}, 1000);
}
};
kitty.grow(); // 3
复制代码
在对象方法的嵌套函数中,this 会指向global对象,这被看做是JavaScript在设计上的一个重大缺陷,通常都会采用一些hack来解决它,以下:bash
let kitty = {
age: 1,
grow: function () {
const self = this;
setTimeout(function () {
console.log(++self.age);
}, 100);
}
}
//或者
let kitty = {
age: 1,
grow: function () {
setTimeout(function () {
console.log(++this.age);
}.bind(this), 100);
}
}
复制代码
如今有了箭头函数,能够很轻松地解决这个问题。app
let kitty = {
age: 1,
grow: function () {
setTimeout(() => {
console.log(this.age);
}, 100);
}
}
复制代码
ES6没有出现以前,面对默认参数都会让人感到很痛苦,不得不采用各类hack,好比说: values = values[0]。如今一切都变得轻松不少。编程语言
function desc(name = ' Peter', age = 5) {
return name + ' is ' + age + ' years old ';
}
desc();
//Peter is 5 years old
复制代码
当一个函数的最后一个参数有 “..."这样的前缀,它就会变成一个参数的数组。模块化
function test(...args) {
console.log(args);
}
test(1, 2, 3);
// [1, 2, 3]
function test2(name, ...args)(
console.log(args);
}
test2('Peter', 2, 3);
//[2,3]
复制代码
它和arguments有以下区别:函数
①Rest参数只是没有指定变量名称的参数数组,而arguments是全部参数的集合;
②arguments 对象不是一个真正的数组,而Rest参数是一个真正的数组,可使用各类方法,好比sort、map 等。
有了这两个理由,是时候告别arguments,拥抱可爱的Rest参数了。
刚才在函数中讲到了使用“...”操做符来实现函数参数的数组,其实这个操做符的魔力不只仅如此。它被称为展开操做符,容许一个表达式在某处展开,在存在多个参数(用于函数调用)、多个元素(用于数组字面量)或者多个变量(用于解构赋值)的地方就会出现这种状况。
若是在以前的JavaScript中,想让函数把一个数组依次做为参数进行调用,通常会以下这样作。
function test(x, y, z) { };
var args = [1, 2, 3],
test.apply (null, args);
复制代码
有了ES6的展开运算符,能够简化这个过程。
function test(x, y, z) { };
let args = [0,1, 2]
test(...args) ;
复制代码
在以前的版本中,若是想建立含有某些元素的新数组,经常会用到splice、concat、push等方法,以下。
var arrl = [1, 2, 3];
var arr2 = [4, 5, 6];
var arr3 = arr1.concat(arr2) ;
console.log(arr3);
// 1.2.3.4.5,6
复制代码
使用展开运算符之后就简便了不少,以下:
let arr1 = (1, 2, 3);
let arr2 = [4,5, 6];
let arr3 = [...arr1, ...arr2];
console.log(arr3);
// 1,2,3,4.5,6
复制代码
数组的展开运算符简单易用,那么对象有没有这个特性?
let mike = {name: 'mike', age: 50};
mlke = {...mike, sex: 'male'};
console.log (mlke);
/*
{
age: 50,
name: "mike" ,
sex: "male"
}
*/
复制代码
对象的展开运算符其实已经被提上日程,只不过它是ES7的提案之一,它可让你以更简洁的形式将一个对象可枚举的属性复制到另一个对象上。这一特性能够借助的Babel和它的插件来实现。
在ES6以前的时代,字符串的拼接老是一件使人不爽的事情,可是在ES6来临的时代,这个痛处也要被治愈了。
//以前总会作这些事情
var name = 'viking';
var a = 'My name is ' + name + '|';
//多行字符串
var longStory = 'This is a long story,'
+ 'this is a long story',
+ 'this is a long story.';
// 有了ES6如今能够这样作
// 注意这里不是引号而是这个符号
let name = 'viking';
let a = `My name is ${name} !`;
let longStory = `This is a long story,
this is a long story
this is a long story~`;
//很是方便,对吧
复制代码
解构语法能够快速从数组或者对象中提取变量,能够用一个表达式读取整个结构。
let foo = ['one', 'two', 'three'];
let [one, two, three] = foo;
console.log(${one}, ${two}, ${three});
//one, two, three
复制代码
let person = {name: 'viking', age: 20};
let {name, age} = person;
console, log(${name}, ${age});
//viking, 20
复制代码
解构赋值能够看做一种语法糖,它受Python语言的启发,能够提升效率。
众所周知,在JavaScript的世界里是没有传统类的概念的,它使用原型链的方式来完成继承,可是声明的方式看起来老是怪怪的,因此ES6提供了class这个语法糖,让开发者能够模仿其余语言类的声明方式,看起来更加明确清晰。须要注意的是,class并无带来新的结构,而只是原来原型链方式的一种语法糖。
class Animal {
//构造函数
constructor(name, age) {
this.name = name;
this.age = age;
}
shout() {
return `My name is ${this.name}, age is ${this.age}`;
}
//静态方法
static foo() {
return 'Here is a static method';
}
}
const cow = new Animal('betty', 2);
cow.shout();
// My name is betty, age is 2
Animal.foo();
//Here is a static method
class Dog extends Animal {
constructor(name, age = 2, color = 'black') {
//在构造函数中能够直接调用super方法
super(name, age);
this.color = color;
}
shout() {
//在非构造函数中不能直接使用super方法
//可是能够采用super(). +方法名宇调用父类方法
return super.shout() + `,color is ${this.color}.`;
}
}
const jackTheDog = new Dog('jack');
jackTheDog.shout();
//"My name is jack, age is 2,color is black"
复制代码
JavaScirpt模块化代码是一个古老的话题,从前端开发这个职业诞生到如今一直都在不断地进化,它的发展也从外一个侧面反映了前端项目愈来愈复杂、愈来愈工程化。
在ES6以前,JavaScript并无对模块作出任何定义,因而先驱者们创造了各类各样的规范来完成这个任务。伴随着Require.js的流行,它所推崇的AMD格式也成了开发者的首选。在这以后,Node.js诞生了,随之而来的是CommonJS格式,再以后browserify的诞生,让浏览器端的开发也能使用这种格式。直到ES6的出现,模块这个观念才真正有了语言特性的支持,如今来看看它是如何被定义的。
//hello.js文件
//定义一个命名为hello的函数
function hello() {
console.log('Hello ES6');
}
//使用export导出这个模块
export hello;
//main.js
//使用import加载这个模块
import { hello } from ' ./hello';
hello();
//Hello ES6
复制代码
上面的代码就完成了模块的一个最简单的例子,使用import和export关键字完成模块的导入和导出。固然也能够完成一个模块的多个导出,请看下面的例子。
//hello.js
export const PI = 3.14;
export function hello() {
console.log('Hello ES6');
}
export let person = {name: 'viking');
//main.js
//使用对象解构赋值加载这3个变量
import {PI, hello, person} from './hello';
//也能够将这个模块所有导出
import * as util from './hello';
console.log (util.PI);
//3.14
复制代码
还可使用default关键字来实现模块的默认导出;
//hello.js
export default function () (
console.log('Hello ES6');
}
//main.js
import hello from './hello';
hello();
//Hello ES6
复制代码
模块的官方定义对于JavaScript来讲是具备划时代意义的,它让各类关于JavaScript模块化标准的争斗落下帷幕,开发者不用再为选择什么样的模块标准而苦恼,每一个人均可以开心地使用ES6的模块标准。
以上就是ES6中比较重要且经常使用的一些语言特性啦!
更多精彩内容欢迎关注个人公众号【天道酬勤Lewis】