1.let和const
ES6用两者来声明变量。
1.1.let
ES5使用var来声明变量
ES5只有全局作用域和函数作用域,没有块级作用域。如下代码所示:
// 示例1 var a = 'a'; if(true) { var a = 'b'; console.log(a); // b } console.log(a);// b // 示例2 var a = []; for (var i=0; i<10;i++) { a[i] = function() { console.log(i); } } a[6](); // 10
示例1:if内区块覆盖了外层变量。
示例2:函数作用域内的是全局变量
而ES6中的let实际上为js新增了块级作用域,它所声明的变量只在let所在代码块内有效。如下代码所示:
// 示例1 var a = 'a'; if(true) { let a = 'b'; console.log(a); // b } console.log(a);// a // 示例2 var a = []; for (let i=0; i<10;i++) { a[i] = function() { console.log(i); } } a[6](); // 6
let声明的变量只在let所在快内有效
1.2.const
const用来声明常量。常量一旦被声明,就不能被改变,如下代码所示:
// 示例1 const name = 'a'; name = 'b'; // Uncaught TypeError: Assignment to constant variable. // 示例2 const name = 'a'; const name = 'b';// Uncaught SyntaxError: Identifier 'name' has already been declared
所以如果定义了一个常量之后,再不小心被人覆盖重赋值的话,会报错,确保变量不被污染。
2.class 和 extends 和 super
ES6的这三个方法对应着ES5的原型、构造函数、继承。ES6提供了更接近传统的方法,引入了Class(类)的概念。新的 Class写法让对象原型的写法更加清晰、更加面向对象、更加通俗易懂。
如下代码所示:
class Person { constructor(name) { this.type = 'person'; this.name = name; } eat(food) { console.log(this.name + ' of ' + this.type + ' eat ' + food); } } let John = new Person('John'); let Rose = new Person('Rose'); John.study('apple'); // John of person eat apple Rose.study('pear'); // Rose of person eat pear
示例首先用class关键字定义了一个”类”,类里有constructor关键字,constructor关键字定义的方法就是构造函数。而this关键字则代表示例对象。简单地说:constructor内定义的方法和属性是实例对象自己的,而constructor外定义的方法和属性则是所有实例对象可以共享的。
Class(类)之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承要清晰和方便很多。如下代码所示:
class Person { constructor(name) { this.type = 'person'; this.name = name; } eat(food) { console.log(this.name + ' of ' + this.type + ' eat ' + food); } } class Student extends Person { constructor(name){ super(name); this.type = 'student'; } study(course) { console.log(this.name + ' of ' + this.type + ' study ' + course); } } let lilei = new Student('lilei'); let hanmeimei = new Student('hanmeimei'); lilei.study('math'); // lilei of student study math hanmeimei.study('music'); // hanmeimei of student study music
示例中定义了一个Student类。该类使用extends关键字继承了Person类的所有属性和方法。
super关键字指代父类的实例(即父类的this对象),子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工,如果不调用super方法,子类就得不到this对象。
如下代码所示:
class Person { constructor() { } eat() { } } class Student extends Person { constructor(){ } study() { } } let lilei = new Student(); // Uncaught ReferenceError: this is not defined
ES6的继承机制,实际上是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this.
3.arrow function
箭头函数最常用,用她来写function比原来的写法要简洁清晰很多,如下代码示例:
// ES5 function (i) { return i + 1; } // ES6 (i) => i + 1;
复杂函数如下:
// ES5 function (x, y) { x = y + 1; return x; } var add = function(x, y){ return x + y; } add(2 ,3); //5 // ES6 (x, y) => {x = y + 1; return x;} let add = (x, y) => x + y; add(2 ,3); //5
除了看起来简洁了以外,arrow function还解决了this对象指代混乱的问题。如下代码示例:
// 混乱 class Person{ constructor(){ this.type = 'person'; } eat(food) { setTimeout(function() { console.log(this.type + ' eat ' + food); }, 1000) } } var John = new Person(); John.eat('apple'); // undefined eat apple // 解决方案1 class Person{ constructor(){ this.type = 'person'; } eat(food) { var self = this; setTimeout(function() { console.log(self.type + ' eat ' + food); }, 1000) } } var John = new Person(); John.eat('apple'); // person eat apple // 解决方案2 class Person{ constructor(){ this.type = 'person'; } eat(food) { setTimeout(function() { console.log(this.type + ' eat ' + food); }.bind(this), 1000) } } var John = new Person(); John.eat('apple'); // person eat apple // 使用arrow function class Person{ constructor(){ this.type = 'person'; } eat(food) { setTimeout(() => { console.log(this.type + ' eat ' + food); }, 1000) } } var John = new Person(); John.eat('apple'); // person eat apple
当我们使用箭头函数时,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。并不是因为箭头函数内部有绑定this的机制,事件原因是箭头函数根本没有自己的this,它的this是继承外面的,因此内部的this就是外层代码块的this。
4.template string
当我们需要插入大段的HTML内容到文档中时,传统的写法非常麻烦,所以之前我们通常会引用一些模板工具库。代码如下:
$("#result").append( "There are <b>" + basket.count + "</b> " + "items in your basket, " + "<em>" + basket.onSale + "</em> are on sale!" );
我们需要用一堆的’+’号来连接文本与变量,而是要ES6的新特性模板字符串“后,我们可以直接这么来写:
$("#result").append(`There are <b>${basket.count}</b> items in your basket, <em>${basket.onSale}</em> are on sale!`);
用反引号(`)来标识起始,用${}来引入变量,而且所有的空格和缩进都会被保留在输出之中。
5.destructuring 解构
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这种被称为解构(destructuring)
如下示例:
// ES5 var name = 'name1'; var age = 20; var c = { name: name, age: age }; console.log(c); // Object {name: "name1", age: 20} // ES6 let name = 'name1'; let age = 20; let c = {name, age}; console.log(c); // Object {name: "name1", age: 20} // ES6 let c = {name: "name1", age: 20}; let {name, age} = c; console.log(name, age); // name1 20
6.default 和 rest
6.1.default
默认值。函数默认参数:
//ES5 function add(lens) { lens = lens || 1; console.log(lens); } add(); // 1 // ES6 function add (lens = 1) { console.log(lens); } add(); // 1 add(2); // 2
6.2.reset
// ES5 function add (params) { console.log(arguments); } add(1, 2, 3); // [1, 2, 3] // ES6 function add (...params) { console.log(params); } add(1, 2, 3); // [1, 2, 3]
参考文章:
30分钟掌握ES6/ES2015核心内容