let 和 const 命令
let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
let name = 'zach' { let name = 'obama' console.log(name) //obama } console.log(name) //zach
使用var声明的变量在for循环的计数器中,变量被泄露为全局变量,如:
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10
上面代码中,变量i是var声明的,在全局范围内都有效。所以每一次循环,新的i值都会覆盖旧值,导致最后输出的是最后一轮的i的值。而使用let则不会出现这个问题。
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
const命令,用来声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI = 3.1415; PI // 3.1415 PI = 3; // TypeError: Assignment to constant variable.
模板字符串
传统的JavaScript语言,输出模板通常是这样写的。
$('#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! `);
用反引号(`)来标识起始,用${}来引用变量。
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 Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } } var p = new Point(1, 2);
上面代码首先用class定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。简单地说,constructor内定义的方法和属性是实例对象自己的,而constructor外定义的方法和属性则是所有实力对象可以共享的,等同于ES5上构造函数的prototype方法和属性。另外,方法之间不需要逗号分隔,加了会报错。
extends继承
Class之间可以通过extends关键字实现继承,super关键字,它指代父类的实例(即父类的this对象)。在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } toName(){ return 'aaa' } } class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // 调用父类的constructor(x, y) this.color = color; } toString() { return this.color + ' ' + super.toString(); // 调用父类的toString() } } var c = new ColorPoint(1,2,'red'); console.log(c.toString()) //red (1, 2)
箭头函数
ES6允许使用“箭头”(=>)定义函数。
// ES5 function(i) { return i + 1; }; // ES6 (i) => i + 1; // ES5 function(x, y) { x++; y--; return x + y; } // ES6 (x, y) => { x++; y--; return x+y }
箭头函数可以绑定this对象,大大减少了显式绑定this对象的写法(call、apply、bind)。
class Animal { constructor(){ this.type = 'animal' } says(say){ setTimeout(function(){ console.log(this.type + ' says ' + say) }, 1000) } } var animal = new Animal() animal.says('hi') //undefined says hi
运行上面的代码会报错,这是因为setTimeout中的this指向的是全局对象。
class Animal { constructor(){ this.type = 'animal' } says(say){ setTimeout( () => { console.log(this.type + ' says ' + say) }, 1000) } } var animal = new Animal() animal.says('hi') //animal says hi
当我们使用箭头函数时,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,它的this是继承外面的,因此内部的this就是外层代码块的this。
module模块
模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
export的写法:
方法一:单个输出 // profile.js export var firstName = 'Michael'; export function multiply(x, y) { return x * y; }; export var year = 1958; 方法二:使用大括号指定所要输出的一组变量 // profile.js var firstName = 'Michael'; export function multiply(x, y) { return x * y; }; var year = 1958; export {firstName, multiply, year}; 方法三:使用as关键字重命名 // profile.js var firstName = 'Michael'; export function multiply(x, y) { return x * y; }; var year = 1958; export { v1 as firstName , v2 as multiply, v2 as year };
export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
export var foo = 'bar'; setTimeout(() => foo = 'baz', 500);
上面代码输出变量foo,值为bar,500毫秒之后变成baz。
import的写法:
import {firstName, multiply, year} from './profile'; //使用as关键字,将输入的变量重命名 import { firstName as surname } from './profile'; //使用用星号(*)指定一个对象,所有输出值都加载在这个对象上面 import * as preson from './profile'; console.log(preson.firstName); console.log(preson.multiply());
export default
export default命令,为模块指定默认输出,一个模块只能有一个默认输出。使用import命令可以用任意名称指向使用export default命令输出的方法。
// import-default.js export default function foo() { console.log('foo'); } // 或者写成 function foo() { console.log('foo'); } export default foo; //main.js import customName from './export-default'; customName(); // 'foo'
Set和Map数据结构
Set它类似于数组,但是成员的值都是唯一的,没有重复的值。
// 删除数组中的重复项 const set = new Set([1, 2, 3, 4, 4]); [...set] // [1, 2, 3, 4] // size:获取数组的长度 const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]); items.size // 5 // add():添加某个值,返回Set结构本身 const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]); items.add(8); [...items] // [1, 2, 3, 4,5,8] // delete:删除某个值,返回一个布尔值,表示删除是否成功 const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]); items.delete(1); [...items] // [ 2, 3, 4,5] // has:返回一个布尔值,表示该值是否为Set的成员 const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]); items.has(1) // clear():清除所有成员,没有返回值 const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]); items.clear()
Array.from方法可以将 Set 结构转为数组。
function dedupe(array) { return Array.from(new Set(array)); } dedupe([1, 1, 2, 3]) // [1, 2, 3]