前言
最近需要使用react进行开发,由于react需要ES6的语法支持,所以希望在进行React学习之前,先了解下ES6的一些特性.(本文主要来源于阮一峰的教程)
一、块级变量 let/const
ES6中支持声明代码块级别的变量,主要有两种方式,let和const,let声明变量,const声明常量。
let
1、只能在声明代码所在的代码块中使用
function hello(){
let a =1;
}
alert(a);
代码会报错
ReferenceError: alert is not defined
at Object.<anonymous> (/code/main.js:4:1)
at Module._compile (module.js:649:30)
at Object.Module._extensions..js (module.js:660:10)
at Module.load (module.js:561:32)
at tryModuleLoad (module.js:501:12)
at Function.Module._load (module.js:493:3)
at Function.Module.runMain (module.js:690:10)
at startup (bootstrap_node.js:194:16)
at bootstrap_node.js:666:3
2、在同一个代码块(不包含子块)只能声明一次
相同代码块
{
let a ="sss";
let a=1; //报错
}
不同代码块
let a=1;
{
let a ="sss"; //不报错
}
3、不存在变量提升
使用let声明的变量,只能在声明代码之后才能使用
4、暂时性死区
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
const
const声明一个只读的常量。一旦声明,常量的值就不能改变。
const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
本质
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
二、函数的扩展
2.1、箭头函数
ES6 允许使用“箭头”(=>)定义函数。
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
建议采用这种方式
var sum = (num1, num2) => { return num1 + num2; }
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
// 报错
let getTempItem = id => { id: id, name: "Temp" };
// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
箭头函数的一个用处是简化回调函数。
// 正常函数写法
var result = values.sort(function (a, b) {
return a - b;
});
// 箭头函数写法
var result = values.sort((a, b) => a - b);
三、Class的使用
3.1、类的声明
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
注意点:
- 方法可以直接声明,不用function修饰
- 类的方法都定义在prototype对象上面
- 类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。
- constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
- 与 ES5 一样,类的所有实例共享一个原型对象。
- 使用#支持私有属性和私有方法
- name 属性
- 使用static声明静态方法,调用时也是通过类直接调用
3.2、继承
ES6使用extends关键字实现类之间的继承
注意点:
1. Object.getPrototypeOf可以获取父类
2. 类的 prototype 属性和__proto__属性
1)子类的__proto__属性,表示构造函数的继承,总是指向父类。
2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
四、模块化
4.1、export
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
4.1.1 直接输出
方式一:
export变量:
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
export函数:
export function multiply(x, y) {
return x * y;
};
4.1.2使用{}输出
方式二:
export变量
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
export函数
function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
4.1.3注意事项
- 另外,export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
- 建议使用{}方式
- export命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错
4.2、import
4.2.1、import指定加载
import {firstName, lastName, year} from './profile.js';
4.2.2、全部加载
除了指定加载某个输出值,还可以使用整体加载,即用星号(*)指定一个对象,所有输出值都加载在这个对象上面。
下面是一个circle.js文件,它输出两个方法area和circumference。
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
现在,加载所有模块方法
import * as circle from './circle';
console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));
4.2.3、注意点
- 模块文件位置
import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js后缀可以省略。如果只是模块名,不带有路径,那么必须有配置文件,告诉 JavaScript 引擎该模块的位置。
import {myMethod} from 'util';
上面代码中,util是模块文件名,由于不带有路径,必须通过配置,告诉引擎怎么取到这个模块。
- import语句会执行所加载的模块,因此可以有下面的写法
import 'lodash';
上面代码仅仅执行lodash模块,但是不输入任何值
4.2.4、export default
使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。
为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。
// export-default.js
export default function () {
console.log('foo');
}
上面代码是一个模块文件export-default.js,它的默认输出是一个函数。
其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。
import customName from './export-default';
customName(); // 'foo'
上面代码的import命令,可以用任意名称指向export-default.js输出的方法,这时就不需要知道原模块输出的函数名。需要注意的是,这时import命令后面,不使用大括号。
export default命令用在非匿名函数前,也是可以的。
// export-default.js
export default function foo() {
console.log('foo');
}
// 或者写成
function foo() {
console.log('foo');
}
export default foo;
注意:
一个模块只能有一个default输出