ECMAScript 6
let 和 const 【重要】
let 和 const 的作用如下:
- 禁止重复声明
- 块级作用域
- 控制修改
相反, 用var声明的变量:可以重复声明、没有块级作用域、不能限制。
let a = "name";
const SCHOOL = "学校";数组 解构
let [a, b, c] = [1, 2, 3];解构的默认值:
在解构赋值时,是允许使用默认值的。举例如下:
javascript{ //一个变量时 let [foo = true] = []; console.log(foo); //输出结果:true } { //两个变量时 let [a, b] = ['生命壹号'] //a 赋值为:生命壹号。b没有赋值 console.log(a + ',' + b); //输出结果:生命壹号,undefined } { //两个变量时 let [a, b = 'smyhvae'] = ['生命壹号'] //a 赋值为:生命壹号。b 采用默认值 smyhvae console.log(a + ',' + b); //输出结果:生命壹号,smyhvae }undefined:相当于什么都没有,此时 b 采用默认值。
null:相当于有值,但值为 null。
对象 解构
let { foo, bar } = { bar: '我是 bar 的值', foo: '我是 foo 的值' };
console.log(foo + ',' + bar); //输出结果:我是键 foo 的值,我是键 bar 的值上方代码可以看出,对象的解构与数组的结构,有一个重要的区别:数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,是根据键来取值的。
字符串 解构
字符串也可以解构,这是因为,此时字符串被转换成了一个类似数组的对象。举例如下:
const [a, b, c, d] = 'smyhvae';
console.log(a);//输出结果:s
console.log(b);
console.log(c);
console.log(d);
console.log(typeof a); //输出结果:string模板字符串
let str = `这是一个字符产`
console.log(str,typeof str)
let str = `<ul>
<li></li>
<li></li>
</ul>`字符串拼接
现在有了 ES6 语法,字符串拼接可以这样写:
var name = 'smyhvae';
var age = '26';
console.log('name:'+name+',age:'+age); //传统写法
console.log(`name:${name},age:${age}`); //ES6 写法注意,上方代码中,倒数第二行用的符号是单引号,最后一行用的符号是反引号(在tab键的上方)。
箭头函数
1.this 是静态的. this始终指向函数声明时所在作用域下的this的值
2.不能作为构造实例化对象
3.不能使用 arguments 变量
定义和调用函数:(传统写法)
function fn1(a, b) {
return a + b;
}
console.log(fn1(1, 2)); //输出结果:3定义和调用函数:(ES6中的写法)
let fn2 = (a, b) => {
return a + b;
};
console.log(fn2(1, 2)); //输出结果:3for ... of 循环
ES6 中,如果我们要遍历一个数组,可以这样做:
let arr1 = [1, 2, 3, 4, 5];
for (let value of arr1) {
console.log(value);
}for ... of既可以遍历数组,也可以遍历Map对象。
参数默认值
传统写法:
function fn(param) {
let p = param || 'hello';
console.log(p);
}ES6 写法:(参数默认值的写法,很简洁)
function fn(param = 'hello') {
console.log(param);
}扩展运算符
注意区分:
- 扩展运算符的格式为
... - rest运算符的格式为
...变量名
function fn(...arg) { //当不确定方法的参数时,可以使用扩展运算符
console.log(arg[0]);
console.log(arg[1]);
console.log(arg[2]);
console.log(arg[3]);
}
fn(1, 2, 3); //方法中定义了四个参数,但只引用了三个参数,ES6 中并不会报错。如果不想让 arr1 和 arr2 指向同一个内存地址,我们可以借助扩展运算符来做:
let arr1 = ['www', 'smyhvae', 'com'];
let arr2 = [...arr1]; //arr2 会重新开辟内存地址
console.log('arr1:' + arr1);
console.log('arr2:' + arr2);
console.log('---------------------');
arr2.push('你懂得'); //往arr2 里添加一部分内容
console.log('arr1:' + arr1);
console.log('arr2:' + arr2);rest运算符
rest 在英文中指的是剩余部分(不是指休息)。我们来举个例子,理解剩余部分的含义:
function fn(first, second, ...arg) {
console.log(arg.length);
}
fn(0, 1, 2, 3, 4, 5, 6); //调用函数后,输出结果为 5从上方例子中可以看出,rest运算符适用于:知道前面的一部分参数的数量,但对于后面剩余的参数数量未知的情况。
字符串的扩展
ES6中的字符串扩展,用得少,而且逻辑相对简单。如下:
includes(str):判断是否包含指定的字符串startsWith(str):判断是否以指定字符串开头endsWith(str):判断是否以指定字符串结尾repeat(count):重复指定次数
举例如下:
let str = 'abcdefg';
console.log(str.includes('a'));//true
console.log(str.includes('h'));//false
//startsWith(str) : 判断是否以指定字符串开头
console.log(str.startsWith('a'));//true
console.log(str.startsWith('d'));//false
//endsWith(str) : 判断是否以指定字符串结尾
console.log(str.endsWith('g'));//true
console.log(str.endsWith('d'));//false
//repeat(count) : 重复指定次数a
console.log(str.repeat(5));Number 的扩展
Number.isFinite(i):判断是否为有限大的数。比如Infinity这种无穷大的数,返回的就是false。Number.isNaN(i):判断是否为NaN。Number.isInteger(i):判断是否为整数。Number.parseInt(str):将字符串转换为对应的数值。Math.trunc(i):去除小数部分。
举例:
//Number.isFinite(i) : 判断是否是有限大的数
console.log(Number.isFinite(NaN)); //false
console.log(Number.isFinite(5)); //true
console.log(Number.isFinite(Infinity)); //false
//Number.isNaN(i) : 判断是否是NaN
console.log(Number.isNaN(NaN));//true
console.log(Number.isNaN(5));//falsse
//Number.isInteger(i) : 判断是否是整数
console.log(Number.isInteger(5.23));//false
console.log(Number.isInteger(5.0));//true
console.log(Number.isInteger(5));//true
//Number.parseInt(str) : 将字符串转换为对应的数值
console.log(Number.parseInt('123abc'));//123
console.log(Number.parseInt('a123abc'));//NaN
// Math.trunc(i) : 直接去除小数部分
console.log(Math.trunc(13.123));//13Symbol
原始数据类型,表示独一无二的值,它是js语言的第七种数据类型,是一种类似于字符串的数据类型
特点:
- Symbol 的值是唯一的,用来解决命名冲突的问题
- Symbol 值不能与其他数据进行运算
- Symbol 定义的对象属性不能使用for...in循环遍历,但可以使用Reflect.ownKeys来获取对象的所有键名
//创建
let s = Symbol();
console.log(s, typeof s); //--->Symbol() "symbol"
let s2 = Symbol("字符串");
let s3 = Symbol("字符串");
console.log(s2===s3); //--->false
//Symbol.for()创建
let s4 = Symbol.for("字符串");
console.log(s4, typeof s4) //--->Symbol(字符串) "symbol"
let s5 = Symbol.for("字符串");
console.log(s4===s5) //--->true向对象中添加方法 up down
let game = {}
let methods = {
up: Symbol(),
down :Symbol()
}
game[methods.up] = function(){}
game[methods.down] = function(){}
let youxi = {
name:"youxi",
[Symbol("say")]:function(){},
[Symbol("look")]:function(){}
}Symbol 内置值
ES6还提供了11个内置值
//类型检测
class Person{
static [Symbol.hasInstance](parm){
console.log("检测类型")
}
}
//迭代器
迭代器(Iterator)
生成器
生成器就是一个特殊的函数
异步编程,纯回调函数,node fs ajax mongodb
function * gen(){
console.log("1111")
yield '一只耳朵';
console.log("222")
yield '一直为八';
console.log("333")
yield '一只手'
}
let iterator = gen()
iterator.next()生成器函数
function one(){
setTimeout(()=>{
console.log(111);
iterator.next();
},1000)
}
function two(){
setTimeout(()=>{
console.log(111);
iterator.next();
},2000)
}
function three(){
setTimeout(()=>{
console.log(111);
iterator.next();
},3000)
}
function * gen(){
yield one();
yield two();
yield three();
}
//调用生成器函数
let iterator = gen();
iterator.next();实例2
//模拟 用户数据 订单数据 商品数据
function getUser(){
setTimeout(()=>{
let data = "用户数据";
iterator.next(data);
},1000)
}
function getOrders(){
setTimeout(()=>{
let data = "订单数据";
iterator.next(data);
},1000)
}
function getGoods(){
setTimeout(()=>{
let data = "商品数据";
iterator.next(data);
},1000)
}
function * gen(){
let users = yield getUser();
console.log(users);
let orders = yield getOrders();
console.log(orders);
let goods = yield getGoods();
console.log(goods);
}
//调用生成器函数
let iterator = gen();
iterator.next();ES6 Promise
function getNumber(){
//实例化 Promise 对象池
const p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
var num = Math.ceil(Math.random()*10); //生成1-10的随机数
if(num<=5){
resolve(num); //成功返回
}
else{
reject('数字太大了'); //失败返回
}
}, 2000);
});
return p;
}
getNumber()
.then(function(data){//成功
console.log('resolved');
console.log(data);
})
.catch(function(reason){//失败
console.log('rejected');
console.log(reason);
});
//3.使用Promise 封装
const p1 = new Promise(function(resolve,rej){
let str = "囔波万!"
resolve(str)
})
p1.then(res=>{
return new Promise(function(resolve,rej){
let str = "囔波吐!"
resolve([res,str])
})
}).then(res=>{
return new Promise(function(resolve,rej){
let str = "囔波思锐!"
res.push(str)
resolve(res)
})
}).then(res=>{
console.log(res);
}).catch(res=>{
console.log("err");
})resolve
成功返回的东西
reject
失败返回
then
成功无限链
catch
获取失败
Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});all
Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。
Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});race
all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,这就是race方法,
比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作,代码如下:
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
}
//延时函数,用于给请求计时
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('图片请求超时');
}, 5000);
});
return p;
}
Promise
.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});Set
//声明一个set
let s = new Set();
let s2 = new Set(["大的","小的","好的","坏的"]);
//元素个数
console.log(s2.size);
//添加新元素
s2.add("喜事儿");
//删除元素
s2.delete("坏的");
//检测
console.log(s2.has("好的"));
console.log(s2);
//清空
s2.clear();Set实践
let arr = [1,2,3,4,5,6,7,2,3,4,2,2];
//1.数组去重
let result = [...new Set(arr)];
console.log(result);
//2.交集
let arr2 = [1,3,4,5];
let res = [...new Set(arr)].filter(item => new Set(arr2).has(item))
//3.并集
let union = [...new Set([...arr,...arr2])];
//4.差集
let diff = [...new Set(arr)].filter(item => !new Set(arr2).has(item))Map
//声明 Map
let m = new Map();
//添加元素
m.set('name','名字');
m.set('change',function(){console.log("我们可以改变你")})
let key = {
school : 'ATGUIGU'
}
m.set(key,['北京','上海','深圳']);
console.log(m);
//size
console.log(m.size);
//删除
m.delete('name');
//获取
console.log(m.get(key));
//清空
m.clear();
//遍历
for(let v of m){
console.log(v);
}Class 类
get set
数组的扩展
扩展1:Array.from()
Array.from(伪数组/可遍历的对象)作用:将伪数组或可遍历对象转换为真数组。
扩展2:Array.of()
Array.of(value1, value2, value3)作用:将一系列值转换成数组。
扩展3:find() 和 findIndex()
方法1:
find(function(item, index, arr){return true})作用:找出第一个满足「指定条件返回true」的元素。
方法2:
findIndex(function(item, index, arr){return true})作用:找出第一个满足「指定条件返回true」的元素的index。
对象的扩展
扩展1(字符串判断)
Object.is(v1, v2)作用:判断两个数据是否完全相等。底层是通过字符串来判断的。
我们先来看下面这两行代码的打印结果:
console.log(0 == -0);
console.log(NaN == NaN);打印结果:
true
false上方代码中,第一行代码的打印结果为true,这个很好理解。第二行代码的打印结果为false,因为NaN和任何值都不相等。
但是,如果换成下面这种方式来比较:
console.log(Object.is(0, -0));
console.log(Object.is(NaN, NaN));打印结果却是:
false
true代码解释:还是刚刚说的那样,Object.is(v1, v2)比较的是字符串是否相等。
扩展2(合并源对象到一个对象)
Object.assign(目标对象, 源对象1, 源对象2...)作用: 将源对象的属性追加到目标对象上。如果对象里属性名相同,会被覆盖。
其实可以理解成:将多个对象合并为一个新的对象。
举例:
let obj1 = { name: 'smyhvae', age: 26 };
let obj2 = { city: 'shenzhen' };
let obj3 = {};
Object.assign(obj3, obj1, obj2);
console.log(obj3);扩展3:__proto__属性
举例:
let obj1 = {name:'smyhvae'};
let obj2 = {};
obj2.__proto__ = obj1;
console.log(obj1);
console.log(obj2);
console.log(obj2.name);上方代码中,obj2本身是没有属性的,但是通过__proto__属性和obj1产生关联,于是就可以获得obj1里的属性。
模块化
语法
- export
- import
ECMAScript 8
async 和 await
async 和 await两种语法结合可以让异步代码像同步代码一样
async函数
- async函数的返回值为promise对象
- promise对象的结果由async函数执行的返回值决定
//async 函数
async function fn(){
return "name"
}
const result = fn();await表达式
- await必须写在async函数中
- await右侧的表达式一般为promise对象
- await返回的时promise成功的值
- await的promise失败了,就会抛出异常,需要通过try...catch捕获处理
//创建promise对象
const p = new Promise((resolve,reject)=>{
resolve("成功");
})
//await 必须要放在 async函数中
async function main(){
let rest = await p;
}
//调用函数
main();async 和 await结合
ECMAScript 9
正则扩展
命名捕获分组
let str = '<a href="http://www.baidu.com">百度</a>'
const reg = /<a href="(?<url>.*)">(?<name>.*)<\/a>/;
const result = reg.exec(str);
console.log(result);
console.log(result.groups.url);正向断言
根据后面的内容判断前面
let str = 'JS1245123你知道吗555拉拉拉'
const reg = /\d+(?=拉拉拉)/;
const result = reg.exec(str);
console.log(result);反向断言
根据前面的内容判断后面
let str = 'JS1245123道吗555拉拉吗123'
const reg = /(?<=道吗)\d+/;
const result = reg.exec(str);
console.log(result);dotAll模式
let str = ` <ul>
<li>
<a href="">肖申克的救赎</a>
<p>上映日期:1994-09-10</p>
</li>
<li>
<a href="">阿甘正传</a>
<p>上映日期:1994-07-06</p>
</li>
</ul>`
const reg = /<li>.*?<a href="">(.*?)<\/a>.*?<p>(.*?)<\/p>.*?<\/li>/gs;
//dot . 元字符 除换行符以外的任意单个字符
let data = [];
while(result = reg.exec(str)){
data.push({title:result[1],time:result[2]})
}
console.log(data);