ES6 简介
ECMAScript 6 简称 ES6,是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了。
ECMAScript 和 JavaScript 的关系:前者是后者的语法规格,后者是前者的一种实现。
新特性
-
let 命令声明的变量
- 不允许重复声明
var a = 1;
var a = 2;
console.log(a); //输出 2
let b = 1;
let b = 2; //报错
console.log(b) ;
- 块级作用域
function f1() {
let n = 5;
if (true) {
let n = 10;
console.log(n); //输出 10
}
console.log(n); // 输出 5
}
- 不存在变量提升
console.log(a); //输出 undefined
var a = 1;
console.log(b); //报错
let b = 1;
-
const 命令声明的常量
- 块级作用域。
- 对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。
- 但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,所以复合类型变量中的数据是可以改变的。
const s = [5, 6, 7];
s = [1, 2, 3]; // 报错
s[2] = 45; // 正常工作
console.log(s); // returns [5, 6, 45]
-
Object.freeze
因为const
并不能保证复合类型的数据是不可改变的,所以我们需要一个新的命令来保证复合类型的只读性,这个命令就是Object.freeze
。
let person = {
name:"XiaoMing",
review:"yes"
};
Object.freeze(person);
person.review = "no"; //这条命令将会被忽略,因为此时person对象是只读的
person.newProp = "age"; // 这条命令也将会被忽略
console.log(obj);
// { name: "XiaoMing", review:"yes"}
-
箭头函数 (Arrow Functions)
在旧的标准中,我们是这样书写函数的:
const myFunc = function() {
const myVar = "value";
return myVar;
}
使用剪头函数,我们可以将其简化为:
const myFunc = () => {
const myVar = "value";
return myVar;
}
还可以进一步简化,我们可以甚至连return都不要:
const myFunc = () => "value"
箭头函数可以传参:
// 将输入的数乘以2,并返回
const doubler = (item) => item * 2;
-
展开运算符 (Spread Operator)
-
解构赋值(Destructuring Assignment)
-
模板字符串 (Template String)
ES6
中引入了一种更强大的字符串写法,被称为模板字符串,用反引号( ` )标识,用法如下:
const person = {
name: "Zodiac Hasbro",
age: 56
};
//用模板字符串方式书写的字符串,并将其赋给greeting变量
const greeting = `Hello, my name is ${person.name}!
I am ${person.age} years old.`;
console.log(greeting);
// 输出:
// Hello, my name is Zodiac Hasbro!
// I am 56 years old.
在上面这段代码中,有三个地方需要我们注意:
- 模板字符串的标识符是反引号(`) 而不是单引号(')。
- 输出的字符串是多行的,我们在也不需要
\n
了。 - 语法
${}
可以用来获取变量,化简了之前用+
来进行字符串拼接的写法。
// es5
var name1 = "bai";
console.log('hello' + name1);
// es6
const name2 = "ming";
console.log(`hello${name2}`);
-
更简洁的定义对象的方法
//ES5
const person = {
name: "Taylor",
sayHello: function() {
return `Hello! My name is ${this.name}.`;
}
};
//ES6,可以将`function`关键词省略
const person = {
name: "Taylor",
sayHello() {
return `Hello! My name is ${this.name}.`;
}
};
// ES5
function people(name, age) {
return {
name: name,
age: age
};
}
// ES6
function people(name, age) {
return {
name,
age
};
}
-
class
ES6
中提供了一种新的语法创建对象,即使用class关键词。需要注意的是,这里的class
关键词只是语法糖,并不具有像传统的面向对象的语言那样的特性。
在ES5
中,我们通常是这样创建构造函数的:
var Person = function(name){
this.name = name;
}
var person1 = new Person('Jim');
利用class
语法糖,我们可以这样写:
class Person {
constructor(name){
this.name = name;
}
}
const person1 = new Person('Jim');
在由class
定义的对象中,我们添加了构造函数constructor()
,构造函数在new
被调用时唤醒,创建一个新的对象。
-
用取值函数和存值函数(getters and setters)来封装对象
在由class
定义的对象中,存值函数和取值函数现在有了自己的关键字get
和set
,用法也更加简单:
class Book {
constructor(author) {
this._author = author;
}
// getter
get writer(){
return this._author;
}
// setter
set writer(updatedAuthor){
this._author = updatedAuthor;
}
}
const lol = new Book('anonymous');
console.log(lol.writer); // anonymous
lol.writer = 'wut';
console.log(lol.writer); // wut
请注意我们调用存值函数和取值函数的方式:lol.writer
。这种调用方式让他们看起来并不像是函数。
-
import、export
https://www.jianshu.com/p/923f642a59af
默认情况下,JavaScript中在模块内的所有声明都是本地的,外部无法访问。如果需要公开模块中部分声明的内容,并让其它模块加以使用,这个时候就需要导出功能,最简单的方式是添加export关键字导出模块。
可以导出的内容包括类、函数以及var、let和const修饰的变量。export命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错,import命令也是如此。
使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。
import命令具有提升效果,会提升到整个模块的头部,首先执行。由于import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js路径可以省略。如果只是模块名,不带有路径,那么必须有配置文件,告诉 JavaScript 引擎该模块的位置。
// 全部导入
import people from './example'
// 将整个模块当作单一对象进行导入,该模块的所有导出都会作为对象的属性存在
import * as example from "./example.js"
console.log(example.name)
console.log(example.getName())
// 导入部分,引入非 default 时,使用花括号
import {name, age} from './example'
// 导出默认, 有且只有一个默认
export default App
// 部分导出
export class App extend Component {};
-
字符串的扩展
includes()
// includes:判断是否包含然后直接返回布尔值
let str = 'hahah';
console.log(str.includes('y')); // false
repeat()
// repeat: 获取字符串重复n次
let s = 'he';
console.log(s.repeat(3)); // 'hehehe'
-
startsWith()
返回布尔值,表示参数字符串是否在源字符串的头部; -
endsWith()
返回布尔值,表示参数字符串是否在源字符串的尾部;
-
数值的扩展
-
Number.isFinite()
检查Infinite(是否非无穷)。 -
Number.isNaN()
检查NaN。 Number.parseInt()
-
Number.parseFloat()
ES6将全局方法parseInt()和parseFloat()移植到了Number对象上。这样是为了逐步减少全局性的方法,使语言逐步模块化。 -
Number.isInteger()
该方法用来判断一个值是否为整数。
-
数组的扩展
-
Array.from()
:将类似数组的对象和可遍历的对象转为真正的数组; -
Array.of()
:将一组数值转换为数组,例如:Array.of(3, 11, 8) //[3,11,8] -
fill()
方法,使用给定值填充数组,例如:new Array(3).fill(7) //[7,7,7] - 数组实例的遍历。
keys()
是对键名的遍历,values()
是对键值的遍历,entries()
是对键值对的遍历;
-
函数的扩展
-
为函数的参数设置默认值
function greeting(name = "Anonymous") {
return "Hello " + name;
}
console.log(greeting("John")); // 输出 Hello John
console.log(greeting()); // 输出 Hello Anonymous
-
rest 参数 (Rest Operator)
ES6
中引入了rest
参数,其形式为...变量名
。通过使用rest
参数,你可以向函数传入不同数量的参数:
function howMany(...args) {
return "You have passed " + args.length + " arguments.";
}
console.log(howMany(0, 1, 2)); // 传入三个参数
console.log(howMany("string", null, [1, 2, 3], { })); // 传入四个参数
rest
参数中的变量代表一个数组,所有数组特有的方法都可以用于这个变量:
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
console.log(a) //输出 [1, 2, 3]
rest
参数之后不能再有其他参数,否则程序会报错。
function add(...values){
let sum = 0;
for(var val of values){
sum += val;
}
return sum;
}
add(2, 5, 3); //10
//add函数是一个求和函数,利用rest参数可以向该函数传入任意数目的参数。
-
扩展运算符
- 扩展运算符,三个点(...),作用是把一个数组转为用逗号隔开的参数序列。
console.log(1,...[2,3,4],5);//1 2 3 4 5;
- 扩展运算符替代数组的apply方法,扩展运算符可以直接把数组拆开,例如:
//ES5
function f(x,y,z){};
var args = [0,1,2];
f.apply(null, args);
//ES6
function f(x,y,z){};
var args = [0,1,2];
f(...args);
- 扩展运算符提供了数组合并的新方法:
//ES5
[1,2].concat(more)
//ES6
[1,2, ...more]
-
Promise
用同步的方式去写异步代码
// 发起异步请求
fetch('/api/todos')
.then(res => res.json())
.then(data => ({
data
}))
.catch(err => ({
err
}));