ECMAScript6学习总结
let和const
let:
- 不允许重复声明
- 没有预解析,没有变量申明提升
let可以在
{}
内声明块级作用域,变量或者函数只在该区域才生效1
2
3
4
5
6{
//该区域为暂存死区
let a = 1;
}
console.log(a);//Uncaught ReferenceError: a is not defined块级作用域相当于闭包形成的局部作用域
1
2
3
4
5
6
7
8
9
10
11
12for (var i = 0; i < 5; i++) {
(function (i) {
setTimeout(function (i) {
console.log(i);
});
})(i);
}
for (let i = 0; i < 5; i++) {
setTimeout(function (i) {
console.log(i);
});
}
实现选项卡功能的三种方式
btns[i].index = i;
1
2
3
4
5
6
7
8
9
10
11
12
13
14var btns = document.querySelectorAll('input');
var divs = document.querySelectorAll('div');
for (var i = 0; i < divs.length; i++) {
btns[i].index = i;
btns[i].onclick = function () {
for (var j = 0; j < divs.length; j++) {
btns[j].className = '';
divs[j].className = '';
}
divs[this.index].className = 'show';
this.className = 'active';
}
}使用闭包
1
2
3
4
5
6
7
8
9
10
11
12for (var i = 0; i < divs.length; i++) {
(function (i) {
btns[i].onclick = function () {
for (var j = 0; j < divs.length; j++) {
btns[j].className = '';
divs[j].className = '';
}
divs[i].className = 'show';
this.className = 'active';
}
})(i);
}使用let
1
2
3
4
5
6
7
8
9
10for (let i = 0; i < divs.length; i++) {
btns[i].onclick = function () {
for (var j = 0; j < divs.length; j++) {
btns[j].className = '';
divs[j].className = '';
}
divs[i].className = 'show';
this.className = 'active';
}
}
const
使用
const
定义常量
,常量在定义之后不可以修改,必须给初始值1
2
3const a = 1;
a = 2;
console.log(a);//Uncaught TypeError: Assignment to constant variable如果常量的属性是一个对象,那么对象的属性是可以修改的
1
2
3
4
5const a = {
name:'hello'
};
a.name = 'world';
console.log(a.name);//world
变量的解构赋值
解构赋值:ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
数组的解构赋值:按照对应的顺序解构。
1
var [a, [b, c]] = [1, [2, 3]];
对象的解构赋值: 按照名字一一对应
1
2
3
4
5
6
7var obj = {
foo: function () {},
o: {},
arr: [],
str: 'abc'
};
var {foo, arr, str} = obj;
字符串扩展
str.repeat(10)
把str复制10次模板字符串
1
2var name ='leo',age = 39;
var str = `你的名字是:${name}你的年龄是:${age}`;str.includes(要查找的字符串, 起始位置 )
返回布尔值,表示是否找到了参数字符串str.startWith(要查找的字符串, 起始位置)
,表示参数字符串是否在源字符串的头部str.endWith(要查找的字符串, 起始位置)
,表示参数字符串是否在源字符串的尾部
数值扩展
Math.trunc(num)
,表示去掉小数点Math.sign(-0)
,判断参数是正数、负数、正0还是负0Math.hypot(3,4)
,返回所有参数的平方和的平方根(勾股定理)
数组扩展
Array.from(字符串|类数组)
,把字符串或者类数组转成真正的数组.Array.of(1,2,3,4,5);
,把参数转为数组.解决new Array(5)只有一个参数时,参数其参数为length的问题.arr.find(function(value,index,arr){})
,它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。1
[1, 2, 3, 4, 5].arr.find((value, index) => value > 3);//4
arr.findIndex(function(){})
,数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。1
2
3[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2arr.fill(填充内容,开始位置,结束为止)
,替换选中的内容1
[1, 2, 3, 4, 5].fill(6,2,4);// [1, 2, 6, 6, 5]
for...of
,用于遍历键值, 而for...in
用于遍历键名,一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以用for…of循环遍历它的成员。1
2
3
4
5
6var arr = [1, 2, 3, 4, 5];
var str = 'hello';
var obj = {a: 1, b: 2, c: 3};
for (var value of arr)console.log(value);//1,2,3,4,5
for (var value of str)console.log(value);//h,e,l,l,o
for (var value of obj)console.log(value);//Uncaught TypeError: obj[Symbol.iterator] is not a functionarr.keys()
,用于对数组键名的遍历1
2
3
4var arr = [1, 2, 3, 4, 5];
for(let index of arr.keys()){
console.log(index);//0,1,2,3,4
}arr.values()
,用于对数组键值的遍历(默认)1
2
3
4var arr = [1, 2, 3, 4, 5];
for(let value of arr.values()){
console.log(index);//1,2,3,4,5
}arr.entries()
,用于对数组键值对的遍历1
2
3
4
5
6
7
8
9
10
11var arr = [1, 2, 3, 4, 5];
for (var [key,value] of arr.entries()) {
console.log(key, value);
/*
* 0 1
* 1 2
* 2 3
* 3 4
* 4 5
* */
}
数组推导: 通过现有数组生成新数组
1
2
3
4
5var arr = [1, 2, 3, 4, 5];
var arr1 = [for(value of arr) value * 2 ];
console.log(arr1);// [2, 4, 6, 8, 10]
var arr2 = [for(value of arr)if(value > 3) value * 2 ];
console.log(arr2);// [8, 10]
对象的扩展
属性的简洁表示法
1
2
3
4
5
6
7
8
9
10
11
12
13function fn(x, y) {
x++;
y++;
/*return {
x: x,
y: y
}*/
return {
x,
y
}
}
console.log(fn(1, 2));//Object {x: 2, y: 3}对象内方法的简洁表示
1
2
3
4
5
6
7
8
9
10var obj = {
name:'momo',
/*showName:function(){
return this.name;
}*/
showName(){
return this.name;
}
};
console.log(obj.showName());属性名表达式: 用表达式作为对象的属性名, 把表达式放在方括号内.
1
2
3
4
5
6
7
8
9var person = {
name:'momo',
[sex]:false,
['get'+'name'](){
return this.name;
}
};
console.log(person.getname());
console.log(person[sex])Object.is(a,b),用来判断两个值是否相等
1
2
3
40===-0;//true
Object.is(0, -0);//false
NaN===NaN;//false
Object.is(NaN,NaN);//trueObject.assign(target,source1,source2,...)
,将source对象的可枚举属性赋值到target对象上。注意:如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。1
2
3
4
5
6
7
8
9
10var obj1 = {};
var obj2 = {
name: 'zMouse'
};
var obj3 = {
name: 'duoduo',
age: 34
};
Object.assign(obj1, obj2, obj3);
console.log(obj1);Object.getPrototypeOf(object)
,用来获取一个对象的prototype对象1
2
3
4
5
6
7
8var Cat = function(name){
this.name = name;
};
Cat.prototype.showname = function(){
return this.name;
};
var c1 = new Cat('momo');
Object.getPrototypeOf(c1);Object.setPrototypeOf(object,prototype)
,用来设置一个对象的prototype对象1
2
3
4
5
6
7
8
9
10
11
12
13var Cat = function(name){
this.name = name;
};
Cat.prototype.showname = function(){
return this.name;
};
var Person = function(){
};
Person.prototype.dadoudou = function(){
};
var c1 = new Cat('momo');
Object.setPrototypeOf(c1, Person.prototype);
console.log(Object.getPrototypeOf(c1))proxy
,提供了一种机制,可以对外界的访问进行过滤和改写1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20var obj = {
a: 1,
b: 2
};
var p1 = new Proxy(obj, {
get(obj, attr){ //当属性访问时触发
return obj[attr];
},
set(obj, attr, value){ // 当属性修改时触发
if (value < 10) {
obj[attr] = value;
}
}
});
p1.a = 5;
console.log(p1.a); // 5
console.log(obj.a); // 5
p1.b = 11;
console.log(p1.b); // 2
console.log(obj.b); // 2
函数扩展
函数参数的默认值,定义默认值的参数必须是尾参数,因为定义默认值之后该参数可忽略
1
2
3
4
function fn(a,b=2) {
return {a, b};
}
console.log(fn(1))//{a: 1, b: 2}
rest参数,用于获取函数的多余参数,rest为参数
1
2
3
4
function fn(a, b, ...re) {
console.log(re)
}
fn(1, 2, 3, 4, 5, 6, 7, 8, 9);
扩展运算符...
,可以将数组或字符串转换为参数序列
获取最大值
1
2
3var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
Math.max.apply(null, arr);
Math.max(...arr); // ... 的作用是将arr的[]去掉将字符串拆分
1
2
3var str = 'hello';
var arr = [...str];
console.log(arr);// ["h", "e", "l", "l", "o"]
箭头函数() => {}
用来作为回掉函数使用
1
2
var f = a => a + 1;
console.log(f(1));//2
注意:
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
不可以使用yield命令,因此箭头函数不能用作Generator函数。
数据结构
Set
Set是一个构造函数,可以传入一个数组或类数组初始化默认值1
2
3
4
5
6
7var set = new Set([1, 2, 3, 4, 5, 6, 6, 6, 6]);
console.log(set);//1,2,3,4,5,6
set.size;//6
set.add(7); //1,2,3,4,5,6,7
set.delete(7); //true
set.has(7); //false
set.clear();
其成员不可以重复,所以可以用set去重
set常用的方法
set.size
:成员的个数,相当于数组的长度set.add(value)
,为Set的实例添加值set.delete(value)
,删除Set实例的值set.has(value)
,判断传入的参数是否为set的成员set.clear()
,清除set中所有的成员
Map
它类似于对象,也是键值对的集合,各种类型的值(包括对象)都可以当作键。Map接受一个数组作为参数,该数组的成员是一个一个表示键值对的数组。1
2
3
4
5var map = new Map([['xiaohong', 80], ['lisi', 78], ['wangwu', 56]]);
//Map{"xiaohong" => 80, "lisi" => 78, "wangwu" => 56}
map.size;//3
map.set('xiaobai',38);//Map {"xiaohong" => 80, "lisi" => 78, "wangwu" => 56, "xiaobai" => 38}
map.get('xiaobai');//38
Map常用的方法
map.size
:成员的个数,相当于数组的长度map.set(key,value)
:添加新键值对map.get(key)
:通过key获取valuemap.delete(key)
:删除map实例的值map.has(key)
:判断传入的参数是否为map的成员map.clear()
:清除map中所有的成员
Map的遍历
forEach
1
2
3
4
5
6
7
8map.forEach(function () {
console.log(arguments);
});
/*
[80, "xiaohong", Map]
[78, "lisi", Map]
[56, "wangwu", Map]
*/for of
1
2
3
4
5
6
7
8for (var i of map) {
console.log(i)
}
/*
["xiaohong", 80]
["xiaohong", 80]
["wangwu", 56]
*/map.keys()
:遍历map的key值1
2
3
4
5
6
7
8for (var i of map.keys()) {
console.log(i)
}
/*
iaohong
xiaohong
wangwu
*/map.values()
:遍历map的value值1
2
3
4
5
6
7
8for (var i of map.values()) {
console.log(i)
}
/*
80
78
56
*/map.entries()
:遍历map的key和value值1
2
3
4
5
6
7
8for (var [key,value] of map.entries()) {
console.log(key,value)
}
/*
xiaohong 80
lisi 78
wangwu 56
*/
Iterator和Symbol
Symbol
ES6引入了一种新的原始数据类型Symbol,表示一个独一无二的ID.它通过Symbol函数生成.1
2
3
4
5
6
7var s = Symbol();
console.log(s);//Symbol()
typeof s;//"symbol"
//独一无二
var s1 = Symbol('test');
var s2 = Symbol('test');
s1===s2;//false
Iterrator
遍历接口:必须部署一个iterator方法,该方法部署在一个键名为Symbol.iterator的属性上,对应的键值是一个函数,该函数返回一个遍历器对象
在Object上部署接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18Object.prototype[Symbol.iterator] = function () {
var keys = Object.keys(this);
var _this = this;
var index = 0;
return {
next(){
if (index < keys.length) {
return {
value: _this[keys[index++]], done: false
}
} else {
return {
value: undefined, done: true
}
}
}
}
};然后可以使用 for of 遍历value
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var obj = {
a: 1,
b: 2,
c: 3,
d: 4
};
for (var value of obj) {
console.log(value);
}
/*
1
2
3
4
*/
Generator函数
可以理解为函数内部状态的遍历器,每调用一次,函数顶走势状态发生一次改变,执行Generator函数会返回一个遍历器对象.
- 两个特征
- function关键字与函数名之间有一个星号
- 函数体内部使用yield语句,定义不同的内部状态
1 | function* fn() { |
Promise
作用是可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
Promise基本用法
1 | new Promise(function (resolve, reject) {}).then(function () {}, function () {}).catch() |
Promise案例
使用回掉函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33var ball1 = document.querySelector('.ball1');
var ball2 = document.querySelector('.ball2');
var ball3 = document.querySelector('.ball3');
function animate(ball, distance, cb) {
setTimeout(function () {
var marginLeft = parseInt(ball.style.marginLeft);
if (marginLeft === distance) {
cb && cb();
} else {
if (marginLeft < distance) {
marginLeft++;
} else {
marginLeft--;
}
ball.style.marginLeft = marginLeft + 'px';
animate(ball, distance, cb);
}
}, 13);
}
animate(ball1, 100, function () {
animate(ball2, 200, function () {
animate(ball3, 300, function () {
animate(ball3, 150, function () {
animate(ball2, 150, function () {
animate(ball1, 150, function () {
})
})
})
})
})
})使用promise
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38function promiseAnimate(ball, distance) {
return new Promise(function (resolve, reject) {
function _animate() {
setTimeout(function () {
var marginLeft = parseInt(ball.style.marginLeft);
if (marginLeft === distance) {
resolve();
} else {
if (marginLeft < distance) {
marginLeft++;
} else {
marginLeft--;
}
ball.style.marginLeft = marginLeft + 'px';
_animate();
}
}, 13);
}
_animate();
});
}
promiseAnimate(ball1, 100)
.then(function () {
return promiseAnimate(ball2, 200)
})
.then(function () {
return promiseAnimate(ball3, 300)
})
.then(function () {
return promiseAnimate(ball1, 300)
})
.then(function () {
return promiseAnimate(ball2, 300)
})
.then(function () {
return promiseAnimate(ball3, 300)
});
Promise.all
1 | var p1 = new Promise(function (resolve, reject) { |
- p4的状态由p1、p2、p3决定,分成两种情况。
- 只有p1、p2、p3的状态都变成resolve,p的状态才会变成resolve,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
- 只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.race
1 | var p4 = Promise.race([p1, p2, p3]); |
- p4的状态由p1、p2、p3决定,分成两种情况。
- 只要p1、p2、p3中一个的状态变成resolve,p4的状态就变成resolve
- 只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p4的回调函数。
class
定义类
ES6以前定义类的方法
1
2
3
4
5
6
7function Cat(name) {
this.name = name;
}
Cat.prototype.getName=function () {
return this.name;
}
var cat1 = new Cat('momo');使用class定义类
1
2
3
4
5
6
7
8
9
10class Cat {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
var cat1 = new Cat('momo');
继承
ES6以前方法的继承
1
2
3
4
5function Dog(name, age) {
Cat.apply(this, arguments);
}
Dog.prototype = new Cat();
Dog.prototype.constructor = Dog;ES6的继承
1
2
3
4
5
6
7
8
9
10
11
12
13class Dog extends Cat {
constructor(name, age) {
//如果需要继承的参数很多,可以使用...rest参数发放
// constructor(age,name,...rests)--super(...rests)
super(name);
this.age = age;
}
getAge() {
return this.age;
}
}
var dog1 = new Dog('maomao', 12);
console.log(dog1.getName());//maomao