你必须要懂的 ES6 语法
简介
ECMAScript 6.0 (简称ES6) ,ES6 的第一个版本,在 2015 年 6 月发布,正式名称就是《ECMAScript 2015 标准》(简称 ES2015)。
参考
站点目录
1. let/const 2. 字符串 3. 函数 4. 类class基本用法 5. export,import
let/const
ES6 中新增加了 let 和 const 两个命令,let用于定义变量,const 用于定义常量, 与var的不同之处在于let,const都是块级作用域,具体请看代码
let or var
// var
if (true) {
var test = 'hello word';
}
console.log(test); // hello word;
// let
if (true) {
let test = 'hello word';
}
console.log(test); // ReferenceError: test is not defined
const
// 情况一
const test = {a: 1};
test.a = 2;
console.log(test); // {a: 2}
// 情况二
const test = 'hello word';
test = 'test'; // TypeError: Assignment to constant variable.
小伙伴们看到这里是不是感觉不可思议,const是定义常量的(常量就是定义过后不可改变的量),不要急,看我慢慢道来, 原因是对于对象型的使用是指针式引用,常量只是指向了对象的指针,对象的内容却已然可以修改,注意数组(array)也是对象,看代码:
let arr = [1, 2, 3, 4];
console.log(typeof arr); // object
那问题来了,怎么判断数组呢,解决这个问题前先了解下js的类型, js中有六种数据类型,包括五种基本数据类型(Number, String, Boolean, Undefined, Null),和一种复杂数据类型(Object),如果对js类型比较模糊,请先学习js基础知识。 回到正题,数组类型判断.
let arr = [1, 2, 3];
console.log(arr instanceof Array); // true
console.log(Array.isArray(arr)); // true
字符串
模板字符串
( `` ) 反引号来定义模板字符串,
// es5
var msg = 'hello word';
var str1 = '<div>' + msg + '</div>';
var str2 = '<div>' +
'<span>' +
'</span>' +
'</div>';
var str3 = '<div>\
<span>\
</span>\
</div>';
// es6
var str1 = `<div>${msg}</div>`;
var str2 = `<div>
<span>
</span>
</div>
`;
注意
- 如果在模板字符串中需要使用反引号,则前面要用反斜杠转义
- 如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
- 模板字符串中嵌入变量,需要将变量名写在${}之中。
- 大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。
- 如果模板字符串中的变量没有声明,将报错。
函数
箭头函数
基本用法
var test = v => v;
// 等同于
var test = function (v) {
return v;
};
//
var test = () => 5;
// 等同于
var test = 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; }
注意点 (1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。 (2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。 (3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。 (4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
函数参数,参数默认值
ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
// es6之前
function log (x, y) {
x = x || 1;
y = y || 2;
return x + y;
}
log(); // 3
log(2,3) // 5
// es6
function log (x = 1, y = 2) {
return x + y;
}
// 或者
let log = (x = 1, y = 2) => x + y;
log(); // 3
log(2,3) // 5
注意
- 使用参数默认值时,函数不能有同名参数。
- 参数变量是默认声明的,所以不能用let或const再次声明。
- 指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。
- 一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。
函数参数
// es6之前
function sum () {
var s = 0;
for (var i in arguments) {
s += arguments[i]
}
console.log(s);
}
sum(1,2,3,4,5,6); // 21
// es6
function sum (...num) {
var s = 0;
for (var i in num) {
s += num[i];
}
console.log(s);
}
sum(1,2,3,4,5,6); // 21
注意
- arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.prototype.slice.call先将其转为数组。
- rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
- 函数的length属性,不包括 rest 参数。
- 只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
class基本用法
基本用法
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
// 基本使用
class Point {
// 类方法
toString () {}
}
typeof Point; // function
类的数据类型就是函数,类本身就指向构造函数。 使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。
// 类的两种方法
class Foo {
// ...
}
const f = new Point(); // Uncaught ReferenceError: Foo is not defined(...)
var Point = class {
// ...
}
const f = new Point(); // 正确
类声明和函数声明不同的一点是,函数声明存在变量提升现象,而类声明不会。即,类必须先声明,然后才能使用,否则会抛出ReferenceError异常。
严格模式
类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。
constructor
constructor方法是一个特殊的类方法,它既不是静态方法也不是实例方法,它仅在实例化的时候被调用。一个类只能拥有一个名为constructor的方法,否则会抛出SyntaxError异常.
如果没有定义constructor方法,这个方法会被默认添加,即,不管有没有显示定义,任何一个类都有constructor方法。
子类必须在constructor方法中调用super方法,否则新建实例时会报错。因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工,如果不调用super方法,子类就得不到this对象。
静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。 如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
// 静态方法
class Foo {
static toString () {
console.log('我是静态方法');
}
point () {
console.log('我不是静态方法');
}
log () {
console.log('我是输出方法');
}
}
class Point extends Foo {
log () {
console.log('重写父级log方法');
}
}
let f = new Foo();
let p = new Point();
Foo.toString(); // 我是静态方法
f.toString(); // TypeError: f.toString is not a function
f.point(); // 我不是静态方法
f.log(); // 我是输出方法
Point.toString(); // 我是静态方法
p.toString(); // TypeError: p.log is not a function
p.point(); // 我不是静态方法
p.log(); // 重写父级log方法
注意
- 如果静态方法包含this关键字,这个this指的是类,而不是实例。
- 静态方法可以与非静态方法重名。
- 父类的静态方法可以被子类继承。
- ES6 明确规定,Class 内部只有静态方法,没有静态属性。
class的getter和setter方法
与 ES5 一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
class Point {
get prop () {
console.log('我是get方法');
}
set prop (value) {
console.log('我是set方法---值为 : ' + value);
}
}
let p = new Point();
p.prop; // 我是get方法
p.prop = 'demo'; // 我是set方法---值为 : demo
继承
Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
class Point {}
class Foo extends Point {}
// Foo就具有Point的所有方法,相当于复制
super
super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。 与this类似,super相当于是指向当前对象的父类,这样就可以用super.xxx来引用父类的成员。
当做函数使用
class A {}
class B extends A {
constructor() {
super(); //ES6 要求,子类的构造函数必须执行一次super函数。
}
}
注意
- super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)。—在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。
- 只能用在构造函数中;
- 在构造函数中用this之前,必须先使用super
当做对象使用
class A {
c() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.c()); // 2
}
}
let b = new B();
上面代码中,子类B当中的super.c(),就是将super当作一个对象使用。这时,super在普通方法之中,指向A.prototype,所以super.c()就相当于A.prototype.c()。 在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
import,export
.ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
注意
-
ES6模块默认使用严格模式,无论是否声明“use strict”
-
ES6 模块之中,顶层的this指向undefined,即不应该在顶层代码使用this。
export
模块是独立的文件,该文件内部的所有的变量外部都无法获取。如果希望获取某个变量,必须通过export输出,
// 方法一
export const a = 1;
export const b = 2;
export function toString () {}
// 方法二
const a = 1;
const b = 2;
function toString () {}
export {a, b, toString};
// 重命名
const a = 1;
const b = 2;
function toString () {}
export {
a as v1,
b as v2,
toString as v3
}
export default
使用import导入时,都需要知道模块中所要加载的变量名或函数名,用户可能不想阅读源码,只想直接使用接口,就可以用export default命令,为模块指定输出
export default function () {}
// 加载时
import toString from './a.js';
toString();
注意
export 与 export default的区别: 两者都是对外暴露接口,export可以在模块中多次使用,export default只能出现一次。
import
export定义了模块的对外接口后,其他JS文件就可以通过import来加载这个模块,
// 方法一
import axios from './axios';
// 方法二
import {toString, a, b} from './mo.js';
// 方法三
import {a as b, n as c} from './mo.js'; // 对方法重命名
import * as reg from './reg.js'; // 把所有方法放入到reg对象中
es6 基础语法就写到这里了,后续还会介绍es6的Promise 的使用方法等,文章节俭与阮大师的es基础入门,如有问题请联系邮箱newwjf@163.com,我会及时回复。