现代浏览器的迅速支持,促使ES6基本成为业界标准。我们今天就来聊一下它的这些新特性:
- Let与Const声明
- 模板字符串
- 对象属性简写
- for...of和for...in
- Symbol数据类型
- 解构赋值
- Set和Map
- 箭头函数
- ES6的扩展
- Promise
- Class类
- 模块化
一、 Let与Const声明
传统var声明的一大局限是变量污染,比如内层变量可能覆盖外层变量,在if或for循环中声明的变量会泄露成全局变量。
为了解决这个问题,ES6引入了let和const命令来进行变量声明。来看下它们的特点和区别:
var——会被视为声明在函数最顶部,有变量提升特性
let——声明局部变量,没有变量提升特性
const——声明常量,声明时必须赋值,且一旦赋值就不能再修改,除非const的是一个对象(对象包含的值可以修改,修改方法见下图)。
const student = { name: 'cc' }
student.name = 'yy';// 不报错
student = { name: 'yy' };// 报错
二、模板字符串
将表达式嵌入字符串中进行拼接。只要将变量放在${}内即可,整个模板字符串用``包裹起来。
var name = "Lucy", age = 16;
`My name is ${name}, I'm ${age}, I can write like this —— ${name+age}.`
三、对象属性简写
设置对象属性时可以不指定属性名:
const name = 'Ming',
age = '18',
city = 'Shanghai';
const student = {
name,
age,
city
};
console.log(student);
四、for...of和for...in
1、for...of遍历迭代器,如数组:
let letters = ['a', 'b', 'c'];
letters.size = 3;
for (let letter of letters) {
console.log(letter); // 结果: a, b, c
}
2、for...in遍历对象属性:
let stus = ["Sam", "22", "男"];
for (let stu in stus) {
console.log(stus[stu]); // 结果: Sam, 22, 男
}
五、Symbol数据类型
用来定义独一无二的值,通过Symbol('字符串')函数来生成。如下图s1和s2,看似一样实则不同:
let s1 = Symbol('web');
let s2 = Symbol('web');
console.log(s1 === s2);
console.log(typeof s1);
console.log(typeof s2);
因为它的值都不相等,所以可以作为对象属性名,有三种方式可以实现——直接赋值、[symbol]、defineProperty(),栗子如下:
// 第一种:直接赋值
let symbol = Symbol();
let a = {};
a[symbol] = 'web';
// 第二种:[symbol]属性
let symbol = Symbol();
let a = {
[symbol]: 'web'
}
// 第三种:defineProperty
let symbol = Symbol();
let a = {};
Object.defineProperty(a, symbol, {value: 'web'});
获取Symbol属性,可以使用Object.getOwnPropertySymbols()。
六、解构赋值
从数组或对象中提取值,对变量进行赋值。要求等号两边的模式相同。
1、使用方法
- 获取数组中的值
var foo = ["one", "two", "three", "four"];
var [one, two] = foo;
console.log(one);
console.log(two);
console.log(three);
var [first, , , last] = foo;
console.log(first);
console.log(last);
var a, b; [a, b] = [1, 2];
console.log(a);
console.log(b);
- 可以方便地交换两个变量的值
var a = 1;
var b = 3; [a, b] = [b, a];
console.log(a);
console.log(b);
- 获取对象中的值
const student = {
name: 'Ming',
age: '18',
city: 'Shanghai'
};
const {
name,
age,
city
} = student;
console.log(name);
console.log(age);
console.log(city);
2、需要注意的问题:
- 不能用undefined赋值。
let [x=1] = [undefined];
x; // 1
- 注意变量作用域问题
let x;
{x} = {x: 1}; // 这里的大括号外要加小括号
七、Set和Map
Set类似数组,Map类似对象,但它们都没有重复的值,可以进行去重操作。
1. 声明方式
new Set();和 new Map();
let a = new Set([1,2,3,4,5]);
let b = new Map([
['name', 'web'],
['des', 'js']
])
2. 共有属性
(1)constructor:构造函数
(2)size:元素个数,代替数组的length
3. 操作方法
(1)共有的:delete、has、clear
let a = new Set([1,2,3,4]);
a.delete(2);
console.log(a); // [1,3,4]
console.log(a.has(3)); // true
a.clear(); // Set(0){}
a.add(6);
(2)Set独有的方法:add()——添加新元素
(3)Map独有的方法
A. set(key, value)——添加新元素
B. get(key)——查找特定数值并返回
3. 共有的遍历方法
- keys()——返回所有键
- values()——返回所有值
- entries()——返回键值对
- forEach(callbackFn, thisArg)——执行callbackFn操作
八、箭头函数
箭头函数有这样几个特点:
1.不需要function关键字,继承当前上下文的this关键字。
2.只有一个参数时,可以省略();
3.只返回一个表达式时,可以省略{}和return。
4.没有arguments变量
5.不会改变this指向——箭头函数没有自己的this,函数内部的this就是外层代码块的this,举个栗子:
var person = {
name: "Lucy",
age: 16,
func: ()=>{
console.log(this);
}
}
person.func(); // window对象
可以发现this是window对象,如果改为普通函数,this指的就是person对象。
那么是不是箭头函数可以完全取代普通函数呢?
并非如此,定义对象时和需要动态this时,不能使用箭头函数。
九、ES6的扩展
ES6在函数、对象、数组对ES5进行了扩展。
1. 函数扩展
(1)默认值:||后 ---> 参数定义后
// es5
function log(x,y) {
y = y || 'web';
console.log(x,y);
}
// es6
function log(x,y="web"){
console.log(x,y);
}
(2)剩余运算符: ...arr表示参数
function web(...arr){
for(let item of arr){
console.log(item);
}
}
web(1,2,3,4,5);
(3)扩展运算符
function add(a,b,c) {
console.log(a);
console.log(b);
console.log(c);
}
var arr = [1,2,3];
add(...arr);
2. 对象的扩展
(1)直接向对象写入变量和函数作为对象的属性和方法
(2)可以使用表达式作为对象的属性
(3)setter和getter
ES6对象的操作方法:
Object.is():比较两个值是否相等。
Object.assign():用于将对象进行合并。Object.getOwnPropertyDescriptor:返回对象属性的描述。
Object.keys()返回一个数组,包含对象自身所有的可枚举属性。
3. 数组的扩展
(1)copyWithin(target,start,end):在当前数组内部,将指定位置的成员复制到其他位置,然后返回当前数组。
(2)target——从该位置开始替换数据。负值表示倒数。
(3)start——从该位置开始读取数据,默认为0。负值表示倒数。
(4)end——到该位置前停止读取数据,默认等于数组长度。负值表示倒数。
(5)find()——找出第一个符合条件的数组成员。
(6)findIndex()——返回第一个符合条件的数组成员的位置,都不符合条件则返回-1。
(7)fill()——填充一个数组,可用于空数组的初始化。
(8)includes()——数组是否包含给定值。
4. 字符串的扩展
(1)s.includes(str)——是否找到了str
(2)s.startsWith(str)——str是否在s的开始位置
(3)s.endsWith(str)——str是否在s的结束位置
它们都支持第2个参数(整型),表示开始匹配的位置
十、Promise
Promise对象表示异步操作的最终状态。它是异步编程的一种解决方案,可以将异步操作用同步操作的流程表达出来,避免层层嵌套,并且提供统一的接口,更方便控制异步操作。
Promise构造函数接收一个函数作为参数,这个函数又有两个参数分别是resolve和reject,如下:
const promiseObj = new Promise(function(resolve,reject){
// code
if(/*异步操作成功*/){
resolve(value);
}else{
reject(error);
}
})
Promise实例生成后,可以用then方法分别指定resolved状态和rejected状态的回调函数。这两个回调函数都接收Promise对象传出的值作为参数,其中第一个回调函数在Promise对象状态变为resolved时调用,第二个在rejected状态时调用(第二个回调函数可选),来段代码:
promiseObj.then(function(value){},function(error){})
十一、Class类
ES6引入Class类,让js的面向对象编程更简单和易于理解。可以使用class构造对象,二是可以使用extends实现继承。
class Point{
constructor(x,y){
this.x = x; // 初始化
this.y = y;
}
toString(){
return `(${this.x},${this.y})`;
}
}
let p = new Point(10,20);
console.log(p.x, p.y);
console.log(p.toString());
// 继承
class ColorPoint extends Point{
constructor(x,y,color){
super(x,y);
this.color = color;
}
showColor(){
console.log('这个点的颜色是'+this.color);
}
}
let cp = new ColorPoint(30,40,'red');
console.log(cp.x, cp.y);
console.log(cp.toString());
cp.showColor();
十二、模块化
模块的功能主要由 export 和 import 组成。每个模块都有自己单独的作用域,通过 export 来规定对外暴露的接口,通过import引用其它模块提供的接口。
1、export导出
可以使用export导出多个变量或函数
- 导出变量/常量
export var name = 'Rainbow'; // 导出变量
export const sqrt = Math.sqrt; // 导出常量
- 导出多个变量
var name = "Rainbow";
var age = 24;
export {
name,
age
}
- 导出函数
export function supModule(args){
return args;
}
2、import导入
定义好模块的输出以后就可以在另一个模块引用了。
- 一条import 语句可以同时导入默认函数和其它变量
import testMethod, {otherMethod} from 'xxx.js';
- 可以为变量起别名
import { otherMethod as om } from 'xxx.js'
十三、其他高级用法
1. Iterator遍历器
它可以为各种数据结构提供统一接口。
2. Genera函数
也是一种异步编程解决方案,返回一个遍历器对象,可以依次遍历Generator函数的每个状态。