es6 学习笔记。
一、定义(声明)变量
**let const var **
块级作用域。let变量,const 常量(不能修改)。
es6之前:var变量
var a=12;
function fn(){
alert(a);//12
}
-----------
var a=12;
function fn(){
alert(a);//undefined
var a=3;
}
二、解构赋值
常用于数据交互,ajax
注意:左右俩边都要相对应。结构赋值可以给默认值。
let [a,b,c]=[10,22,33];
console.log(a,b,c);//10 22 33
let [a,b,c]=[10,[22,33]];
console.log(a,b,c);//10 [22,33] undefined
let [a,[b,c]]=[10,[22,33]];
console.log(a,b,c);//10 22 33
let [a,b,c]=[12,22];
console.log(a,b,c);//12,22,undefined
let [a,b,c='默认']=[12,22];
console.log(a,b,c);//12,22,默认
let [a,b,c=‘默认’]=[12,22,undefined];
console.log(a,b,c);//12,22,默认
let [a,b,c=‘默认’]=[12,22,null];
console.log(a,b,c);//12,22,null
三、字符串模板与新增字符串
一、字符串模板: ``反引号+${}。
之前:
let name = ‘张三’;
let age =16;
let src='我叫'+name+'今年'+age+'岁';
console.log(src);//我叫张三今年18岁
let name = ‘张三’;
let age =16;
let src=`我叫${name}今年${age}岁`;
console.log(src);//我叫张三今年18岁
传统上,JavaScript 只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。
includes,startsWith,endsWith
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
这三个方法都支持第二个参数,表示开始搜索的位置。
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
上面代码表示,使用第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。
新增字符串查找:includes
(无法判断后缀)
str.index(要找到的东西) 返回索引(位置从第几位开始)
str.includes(要找到的东西) 返回值 true、false
判断浏览器
if(navigator.userAgent.includes('chrome')){
alert('chrome');
}else{
alert('! chrome');
}
字符串以什么开头结尾
str.startsWith(检查的东西)
-
http
-
地址
str.endsWith(检查的东西)
-
.png
重复字符串:repeat
(次数)
let str='我';
alert(str.repeat(3));//我我我
填充字符串(es2016,es6即ES2015,在2015年6月提出。):
str.padStart( 整个字符串长度(原本的+打算加的),填充的东西);
往前填充str.padEnd(整个字符串长度(原本的+打算加的),填充的东西);
往后填充
let str=‘Apple’;
let padStr=‘xxx’;
srt.padStart(str.length+padStr.length,padStr);// xxxApple
四、函数默认参数、箭头函数、剩余参数
ES5中不能直接为函数的参数指定默认值,只能通过以下的变通方式:
function show(a,b){
a=a || '我';
b=b || 'ai';
}
当传入的参数为0或者false时,会直接取到后面的值,而不是传入的这个参数值。
剩余函数 :rest() ...
ES6 引入 rest 参数(形式为“…变量名”),用于获取函数的多余参数,这样就不需要使用arguments
对象了。
作用:可以展开或者收缩函数,也可以求剩余
function fun(a, ...rest) {
console.log(a)
console.log(rest)
}
fun(1) // 1 []
fun(1, 2, 3, 4) //1 [2,3,4]
又比如,在前面定义2个参数
function fun(a, b, ...rest) {
console.log(a, b)
console.log(rest)
}
fun(1, 2) // 1 2 []
fun(1, 2, 3, 4) 1 2 [3,4]
注意:剩余参数后面不能跟其他参数,否则会报错
function func(a, ...rest, b) {}//报错
当使用剩余参数后,函数的length属性会发生一些变化
function func(a, b, ...rest) {
}
func.length // 2
即length不包含rest,为2。
剩余参数前面可以不跟其他参数,即一个参数也没有。如
function func(...rest) {
console.log(rest)
}
func(1) // [1]
func(1, 2, 3, 4) // [1,2,3,4]
也可以做展开:
let str=[1,2,3,4];
alert(...str);//1,2,3,4
注意:rest不能和arguments一起使用,会报错
function func(...rest) {
console.log(rest)
console.log(arguments)
}
rest
和arguments
的区别是什么呢?
arguments是一个伪数组(Array-like)
剩余参数是一个真正数组(Array),具有Array.prototype上的所有方法
arguments上有callee,callee上有caller
转换数组:
Array.prototype.slice.apply(arguments)
…Array
箭头函数
( )= > { 语法 }
function show(a=1){
alert(a);//1
}
show();//1
let show = (a=2)=>{
alert(a);//2
}
show();//2
注意:
1, this 定义函数所在的对象,不再是运行时所在的对象
2. 箭头函数里面没有arguments ,用 …
3. 箭头函数不能当构造函数
let show =()=>{
this.name='abc';
}
let s =new show();
alert(s.name);//报错
var id=2;
let show =()=》{
id=1;
setTimeout(()=》{
alert(this.id);
},1000)
}
show(); // 1
let str={1,2,3,4};
let show = ()=>{
alert(arguments);
}
show(str); //报错
let str={1,2,5,4};
let show = (a)=>{
alert(..a.sort());
}
show(str); /1,2,4,5
sort():排序
五、数组
1.forEach() —2.map()—3.filter()—5.some()—6.every() 都可以接受俩个参数,一个为循环回调函数,一个为this指向
1.forEach()
用来代替for循环:
let arr = [1,2,3,4];
arr.forEach(function(item,index,arr){
console.log(this,item,index,arr);
},555);
555 1 0 [1,2,3,4]
555 2 1 [1,2,3,4]
555 3 2 [1,2,3,4]
555 4 3 [1,2,3,4]
arr.forEach((item,index,arr){
console.log(this,item,index,arr);
},555);
改为箭头函数,this指向还是window
2.map()
map返回一个新的数组,可以改变数组的值,需要配合 return;若没有 return ,相当于 forEach
let arr = [1, 2, 3];
let newArr = arr.map((item, index, arr) => {
return item * 2;
})
console.log(arr) // [1, 2, 3]
console.log(newArr) // [2, 4, 6]
let arr=[1,2,3,4];
let res=arr.map((item, index, arr)=>{
return Math.pow(item,2);
return item**2;
});
console.log(res);
3.filter()
filter可以过滤数组,包含满足条件的数组项,返回一个新数组
可以用于过滤不要的元素,retrun true 就留下来
let arr = [1, 2, 3];
let newArr = arr.filter((item, index, arr) => {
return item <= 2;
})
console.log(arr) // [1, 2, 3]
console.log(newArr) // [1, 2]
4.some()
some返回布尔值,如果有一个满足条件的值则返回 true
let arr = [1, 2, 3];
let result = arr.some((item, index, arr) => {
return item < 2;
})
console.log(result) // true
5.every()
every返回布尔值,如果所有数组项都满足条件则返回true
let arr = [1, 2, 3];
let result = arr.every((item, index, arr) => {
return item < 2;
})
console.log(result) // false
--
let arr = [1, 2, 3];
let result = arr.every((item, index, arr) => {
return item > 0;
})
console.log(result) // true
6.reduce()----从左往右
接受的参数 prev 上一个 cur 当前 index arr
求数组的和
let arr=[1,2,3,4,5,6,7,8,9,10];
let res=arr.reduce((prev,cur,index,arr)=>{
return prev +cur;
});
console.log(res);
求次方:2的3次方
Math.pow(2,3);
es2017 : 2**3
7.reduceRight()—从右往左
同上
8 for…of 循环
keys() 数组的下标
entries() 数组的某一项
let arr=[1,2,3,4];
for(let val of arr){
console.log(val);//1,2,3,4
}
let arr=[1,2,3,4];
for(let index of arr.keys()){
console.log(val);//0,1,2,3
let arr=[1,2,3,4];
for(let item of arr.entries()){
console.log(item);//[0,1][1,2][2,3][3,4]
let arr=[1,2,3,4];
for(let [key,item] of arr.entries()){
console.log(item);//0,1 1,2 2,3 3,4
9 Array.from()
- Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组。
- 所谓类数组对象,最基本的要求就是具有length属性的对象。
- 将一个类数组对象转换为一个真正的数组,必须具备以下条件:
1、该类数组对象必须具有length属性,用于指定数组的长度。如果没有length属性,那么转换后的数组是一个空数组。
2、该类数组对象的属性名必须为数值型或字符串型的数字
ps: 该类数组对象的属性名可以加引号,也可以不加引号
let json={
0:'apple',
1:'banana',
2:'orange'
}
let str=Array.from(json);
console.log(str); //undefined, undefined, undefined
let json={
0:'apple',
1:'banana',
2:'orange' ,
length:3
}
let str=Array.from(json);
console.log(str); //apple,banana,orange
Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。如下:
let arr = [12,45,97,9797,564,134,45642]
console.log(Array.from(arr, item => item + 1)) // [ 13, 46, 98, 9798, 565, 135, 45643 ]
10Array.of()
Array.of( )方法总会创建一个包含所有传入参数的数组,而不管参数的数量与类型:
let items = Array.of(1, 2);
console.log(items.length); // 2
console.log(items[0]); // 1
console.log(items[1]); // 2
items = Array.of(2);
console.log(items.length); // 1
console.log(items[0]); // 2
11 arr.find()
查找元素,第一个符合条件的,没有则undefined
let arr=[1,2,3,4];
let str=arr.find((val,index,arr)=>{
return val>2;
});
console.log(str);//3,4
12 arr.findIndex()
查找位置,第一个符合条件的,没有则返回 -1
13 arr.fill
填充
let s=new Array(6);
s.fill('wo');
console.log(s);//wo,wo,wo,wo,wo,wo
s.fill('wo',2,4);
console.log(s);//null,null,wo,wo,wo,null
–
六、对象简洁语法与对象新增
- 同名的属性可以省略不写
- 对象中的方法中的 : function 可以省略不写
- 方法简写,不要用箭头函数(建议)
let name ='xiao';
let age = 16;
let json={
name, //name:name,
age , //age :age ,
show(){
return 3;
} //show:function(){return 3;};
};
console.log(json.name,json.age,json.show());//xiao,16,3
Object.is()
ES5 比较两个值是否相等,只有两个运算符:相等运算符( ==
) 和严格相等运算符(===
)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。
ES6 提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
console.log(NaN == NaN); //false
console.log(Number.isNaN(NaN) ); // true
let b = Object.is(NaN,NaN);
console.log(b);//true
Object.is(+0,-0);//false
Object.assign()
- 用来合并对象
语法:Object.assign(target, …sources) target: 目标对象,sources: 源对象
用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target); // Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget); // Object { a: 1, b: 4, c: 5 }
- 复制对象
const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
Object.keys() 数组的下标
Object.entries() 数组的某一项
let {keys,values,entries} = Object;
let json={
a:1,
b:2,
c:3
};
for(let key of keys(json)){
console.log(key);//a,b,c
}
for(let value of values(json)){
console.log(value);//1,2,3
}
for(let item of entries(json)){
console.log(item );// [a:1],[b:2],[c:3]
}
for(let [key,value] of entries(json)){
console.log([key,value]);// a 1, b 2,c 3
}
七、Promise
作用:解决异步回调
传统方式:大部分用回调函数,事件
ajax(url,{
//获取token
ajax(url,()=>{
//用token获取用户信息
ajax(url,()=>{
//用用户信息获取用户相关新闻
});
});
});
语法:new Promise( function (resolve, reject) {}).then(res=>{}).catch(err=>{});
new Promise(
function (resolve, reject) {
// 一段耗时的异步操作
// resolve('成功') // 数据处理完成
// reject('失败') // 数据处理出错
}
).then(
(res) => {console.log(res)}, // 成功
(err) => {console.log(err)} // 失败
)
new Promise( function (resolve, reject) {}).then(res=>{}).catch(err=>{});
例子:
let a=10;
let ss = new Promise(
function (resolve, reject) {
if(a==10){
resolve('成功')
}else{
reject('失败')
};
}
).then(
res => {console.log(res)}, // 成功
err => {console.log(err)} // 失败
)
Promise.resolve('aaa')
: 将现有的东西,转换为一个Promise对象,resolve 成功状态
等价于:
new Promise(resolve=>{
resolve(‘aaa’);
});
Promise.reject('bbb')
: 将现有的东西,转换为一个Promise对象,reject 失败状态
等价于:
new Promise((reject,resolve)=>{
reject(‘bbb’);
});
Promise.all({p1,p2,p3});
把 Promise 打包,放到一个数组里面,打包完还是一个promise对象;
必须确保p1,p2,p3 所有的 Promise.resolve('aaa对象,状态都是成功的,
Promise.race({p1,p2,p3});
把 Promise 打包,放到一个数组里面,打包完还是一个promise对象;
有一个 Promise.resolve('aaa对象,就返回
let p1= Promise.resolve('aaa');
let p2= Promise.resolve('bbb');
let p3= Promise.resolve('ccc');
Promise.all({p1,p2,p3}).then(res=>{
//console.log(res);
let [res1,res2,res3]=res;
console.log(res1,res2,res3);//aaa,bbb,ccc
});
例子:模仿用户登录,获取信息
let s=1; //状态码
let userlogin=(resolve,reject)=>{
setTimeout(()=>{
if(s == 1){
resolve({data:'用户登录成功',msg:'',token:''});
}else{
reject('用户登录失败');
};
},1000);
};
let getUserInfo=(resolve,reject)=>{
setTimeout(()=>{
if(s == 1){
resolve({data:'获取用户信息成功',msg:'',token:''});
}else{
reject('获取用户信息失败');
};
},1000);
};
new Promise(userlogin).then(res=>{
console.log('用户登录成功');
return new Promise(getUserInfo);
}).then(res=>{
console.log('获取用户信息成功');
console.log(res);
});
八、模块化
es5之前的javascript中是没有模块化概念的。如果要进行模块化操作,需要引入第三方的类库。随着技术的发展,前后端分离,前端的业务变的越来越复杂化。直至ES6带来了模块化,才让javascript第一次支持了module
。ES6的模块化分为导出(export
)与导入(import
)两个模块。
在ES6中每一个模块即是一个文件,在文件中定义的变量,函数,对象在外部是无法获取的。如果你希望外部可以读取模块当中的内容,就必须使用export来对其进行暴露(输出)。
import 特点:
a)可以是绝对路径,也可以是相对路径
b)import 模块只会导入一次,无论你引入多少次
c)有提升效果,会自动提升到顶部
d)导出去的模块内容,如果里面有定时器更改,外面也会改动
e)不能动态引入,要动态引入得用import()
import()特点:
按需加载,可以动态引入,默认import语法不能写到if之类里面;
返回值,是一个promise 对象
错误:
<script type="module">
let a=1;
if(a == 1){
import a from './test1.js';
}else{
import a from './test2.js';
};
</script>
正确:
import('./modules.js').then(res=>{
console.log(res);
});
动态引入+promise
<script type="module">
Promise。all([
import('./modules/1.js');
import('./modules/2.js');
]).then(([m1,m2])=>{
console.log(m1);
console.log(m2);
});
</script>
test.js文件:
let myName="laowang";
let myAge=90;
let myfn=function(){
return "我是"+myName+"!今年"+myAge+"岁了"
}
export {
myName,
myAge,
myfn
}
/******************************接收的代码调整为**********************/
<script type="module">
import {myfn,myAge,myName} from "./test.js";
console.log(myfn());//我是laowang!今年90岁了
console.log(myAge);//90
console.log(myName);//laowang
</script>
如果你不想暴露模块当中的变量名字,可以通过as来进行操作:
let myName="laowang";
let myAge=90;
let myfn=function(){
return "我是"+myName+"!今年"+myAge+"岁了"
}
export {
myName as name,
myAge as age,
myfn as fn
}
/******************************接收的代码调整为**********************/
import {fn,age,name} from "./test.js";
console.log(fn());//我是laowang!今年90岁了
console.log(age);//90
console.log(name);//laowang
也可以直接导入整个模块,将上面的接收代码修改为:
import * as info from "./test.js";//通过*来批量接收,as 来指定接收的名字
console.log(info.fn());//我是laowang!今年90岁了
console.log(info.age);//90
console.log(info.name);//laowang
默认导出(default export)
一个模块只能有一个默认导出,对于默认导出,导入的名称可以和导出的名称不一致。
/******************************导出**********************/
export default function(){
return "默认导出一个方法"
}
/******************************引入**********************/
import myFn from "./test.js";//注意这里默认导出不需要用{}。
console.log(myFn());//默认导出一个方法
可以将所有需要导出的变量放入一个对象中,然后通过default export进行导出
/******************************导出**********************/
export default {
myFn(){
return "默认导出一个方法"
},
myName:"laowang"
}
/******************************引入**********************/
import myObj from "./test.js";
console.log(myObj.myFn(),myObj.myName);//默认导出一个方法 laowang
同样也支持混合导出
/******************************导出**********************/
export default function(){
return "默认导出一个方法"
}
export var myName="laowang";
/******************************引入**********************/
import myFn,{myName} from "./test.js";
console.log(myFn(),myName);//默认导出一个方法 laowang
重命名export和import
如果导入的多个文件中,变量名字相同,即会产生命名冲突的问题,为了解决该问题,ES6为提供了重命名的方法,当你在导入名称时可以这样做:
/******************************test1.js**********************/
export let myName="我来自test1.js";
/******************************test2.js**********************/
export let myName="我来自test2.js";
/******************************index.js**********************/
import {myName as name1} from "./test1.js";
import {myName as name2} from "./test2.js";
console.log(name1);//我来自test1.js
console.log(name2);//我来自test1.js
九、class类
类:constructor构造方法
es5中:
es6中:
第一、首先要明白,ES6的class只是一个语法糖,class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已,其实还是使用ES5的构造函数来实现的。
可以看到类里面有一个constructor
方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES5的构造函数Point,对应ES6的Point类的构造方法;ES5的构造函数原型prototype上的方法对应ES6的 class类里面写的函数,即ES6的各种现象都可以使用ES5进行解释。
ES6的类中的定义方法的时候,前面不需要加function关键字,另外方法直接不能加逗号分隔,加了会报错;
类里面是写语句的,所以不能写逗号,但可以写分号的,因为里面的一个方法就是一个语句;
类的静态方法 static
只能用类来调用:
class Pro{
constructor(){
}
showNmae(){
return '这是showNmae方法';
}
static aaa(){
return '这是静态方法';
}
}
let p1=new Pro();
console.log(p1.showNmae);
console.log(Pro.aaa());
继承 extends
类名:首字母大写,
super()
//父类
class Prson{
constructor(name){
this.name = name;
}
showName(){
console.log('父类');
return `这是showName方法,名字为:${this.name}`;
}
}
//子类
class Student extends Prson{
constructor(name,skill){ //arg 接受的参数
super(arg);
this.skill=skill;
}
showSkill(){
return '我的技能${skill}'
}
showName(){
super.showName(); //父类的方法执行
console.log('子类');
return `这是showName方法,名字为:${this.name}`;
}
}
let str1 = new Student('ling','上学');
console.log(str1.showName());//这是showName方法,名字为:ling
console.log(str1.showSkill());//我的技能上学
十、symbol与generator函数
Symbol是由ES6规范引入的一项新特性,它的功能类似于一种标识唯一性的ID。
每个Symbol实例都是唯一的。因此,当你比较两个Symbol实例的时候,将总会返回false:
let s1 = Symbol();
let s2 = Symbol('another symbol');
typeof s1 // 'symbol'
let s1 = Symbol()
let s2 = Symbol('another symbol')
let s3 = Symbol('another symbol')
s1 === s2 // false
s2 === s3 // false
Symbol类型的key是不能通过Object.keys()或者for…in来枚举的,它未被包含在对象自身的属性名集合(property names)之中。所以,利用该特性,我们可以把一些不需要对外操作和访问的属性使用Symbol来定义。
let obj = {
[Symbol('name')]: 'aaa',
age: 18,
title: 'Engineer'
}
Object.keys(obj) // ['age', 'title']
for (let p in obj) {
console.log(p) // 分别会输出:'age' 和 'title'
}
Object.getOwnPropertyNames(obj) // ['age', 'title']
JSON.stringify(obj) // {"age":18,"title":"Engineer"}
generator函数
: 解决异步深度嵌套
在Javascript中,一个函数一旦开始执行,就会运行到最后或遇到return时结束,运行期间不会有其它代码能够打断它,也不能从外部再传入值到函数体内而Generator
函数(生成器)的出现使得打破函数的完整运行成为了可能,其语法行为与传统函数完全不同Generator
函数是ES6提供的一种异步编程解决方案,形式上也是一个普通函数,但有几个显著的特征:
– function关键字与函数名之间有一个星号 “*” (推荐紧挨着function关键字)
– 函数体内使用 yield 表达式,定义不同的内部状态 (可以有多个yield)
– 直接调用 Generator函数并不会执行,也不会返回运行结果,而是返回一个遍历器对象(Iterator Object)
– 依次调用遍历器对象的next方法,遍历 Generator函数内部的每一个状态
function* generator(){
yieId 'welcome';
yieId 'to';
yieId 'shanghai';
return 'wo';
}
let g1 = generator();
console.log(g1); // 返回的是一个Iterator对象
console.log(g1.next()); // {value: "welcome", done: false},value 表示返回值,done 表示遍历还没有结束
console.log(g1.next()); // {value: "to", done: false},value 表示返回值,done 表示遍历还没有结束
console.log(g1.next()); // {value: "shanghai", done: false},value 表示返回值,done 表示遍历还没有结束
console.log(g1.next()); // {value: "wo", done: true},value 表示返回值,done 表示遍历结束
console.log(g1.next()); // {value: "undefined", done: true},value 表示返回值,done 表示遍历结束
--------
for ..of 可以自动遍历generator,但是不会遍历return,
解构赋值,也是不会遍历return的
---------
for(let a of generator){
console.log(generator); //welcome to shanghai
}
let [a,b,c]=generator();
console.log(generator); //welcome to shanghai undefined
let [a,...b]=generator();
console.log(a); //welcome
console.log(b); // to shanghai
十一、async 、await
async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。另外还有一个很有意思的语法规定,await 只能出现在 async 函数中。
如果需要通过 await 来调用一个 async 函数,那这个调用的外面必须得再包一个 async 函数,然后……进入死循环,永无出头之日……
这个问题的关键在于,async 函数是怎么处理它的返回值的!
**async 函数返回的是一个 Promise 对象。**从文档中也可以得到这个信息。async 函数(包含函数语句、函数表达式、Lambda表达式)会返回一个 Promise 对象,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。
async 函数返回的是一个 Promise 对象,所以在最外层不能用 await 获取其返回值的情况下,我们当然应该用原来的方式:then() 链来处理这个 Promise 对象,
读取文件例子与上面的Promise ,generator比较
const fs = require('fs');
const readfile = function(fileName){
return new Promise((resolve,reject)=>{
fs.readFile(fileName,'utf-8',(err,data)=>{
if(err){
console.log(err);
}else{
console.log(data);
}
});
});
}
---------------------------
//Promise 的方法
readFile(fileName1).then((res)=>{
console.log(res.toString());
return readFile(fileName2);
}).then((res)=>{
console.log(res.toString());
return readFile(fileName3);
}).then((res)=>{
console.log(res.toString());
});
---------------------------
//generator的方法
function* gen(){
yieId readFile(fileName1);
yieId readFile(fileName2);
yieId readFile(fileName3);
}
let g1=gen();
g1.next().value.then(res=>{
console.log(res.toString());
return g1.next().value;
})then(res=>{
console.log(res.toString());
return g1.next().value;
})then(res=>{
console.log(res.toString());
return g1.next().value;
});
---------------------------
async 的方法
async function fn(){
let f1 = await readFile(fileName1);
console.log(f1);
let f2 = await readFile(fileName2);
console.log(f2);
let f3 = await readFile(fileName3);
console.log(f3);
}
fn();
async的特点:
- await 只能放到 async 中
- 相比 genrator 语义化
- await 后面可以是promise 对象,也可以是 数字,字符,布尔值
- async 返回的是一个 promise 对象
- 只要 await 语句后面 promise 状态 为 reject ,整个函数会中断执行
如何解决 async 函数中抛出错误,影响后续代码”:
- try{
}catch(e){
}
async function fn(){
try{
await Promise.reject('出问题');
}catch(e){ }
let a =await Promise.resolve('aaa');
}
fn().then(res=>{
console.log(res);
});
- promise 本身
async function fn(){
await Promise.reject('出问题').catch(err=>{
console.log(res);
});
let a =await Promise.resolve('aaa');
}
fn().then(res=>{
console.log(res);
});
建议:网络请求容易出现问题,任何有 async 的地方最好加上 try—catch
async function fn(){
try{
let f1 = await readFile(fileName1);
let f2 = await readFile(fileName2);
let f3 = await readFile(fileName3);
}catch(e){ }
console.log(f1);
console.log(f2);
console.log(f3);
}
fn();
十二、数据结构 Set与WeakSet
Set 类数组,里面不允许有重复值。
我们可以利用这一唯一特性进行数组的去重工作。
let set = new Set([1, 2, 2, 3, 4, 3, 5])
console.log( set); //Set { 1, 2, 3, 4, 5 }
多数组的合并去重
let arr1 = [1, 2, 3, 4]
let arr2 = [2, 3, 4, 5, 6]
let set7 = new Set([...arr1, ...arr2])
console.log( set7)// Set { 1, 2, 3, 4, 5, 6 }
setArr.add(); 添加
setArr.delete(); 添加
setArr.has(); 检测,有没有
setArr.size 查看个数
setArr.clear(); 清空
数组的去重:
let Arr =[1,2,3,4,4,4];
let newArr =[...new Set(Arr)];
console.log(newArr);// 1,2,3,4
let a = new Set([1,2,3]);
set = new Set([...a].map(val=>val*2));
console.log(set);//Set{2,4,6}
Set 存储数组
WeakSet 存储 json 对象,没有size
十三、数值(数字)的变化
二进制( Binary ):前面加 0b
let number = 0b010101;//21
八进制(octal):0o 数字0加字母o
let number = 0o666;//438
十六进制:#ccc
判断一个值是否是数字
以前:
- Number ----- parseInt() 、parseFloat()
es6 : - Number.isFinite();
Number.isInteger();
判断数字是否为整数
安全整数:2的53次方减一 , -(253-1)-----(253-1)
Number.isSafeInteger();
Math 新增:
Math.trunc()
截断。截取(只保留整数部分)
Math.trunc(4.22) //4
Math.sign();
判断一个数是整数,负数,还是0
Math.sign(-5) //-1
Math.sign(5) //1
Math.sign(0) //0
Math.sign(-0) //-0
Math.sign(abc) //NaN
Math.cbrt()
立方根
Math.cbrt(27) // 3
十四、es2018 (es9)新增的东西
命名捕获
语法:(?<名字>)
之前:
let str ='2020-02-22';
let reg =/(\d{4})-(\d{2})-(\d{2})/;
let dataArr =str.match(reg);
let year = dataArr[1];
let year = dataArr[2];
let year = dataArr[3];
let str ='2020-02-22';
let reg =/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
let {year,month,day}=str.match(reg).groups;
十五、proxy
es 6 proxy:
- 代理
- 扩展(增强)对象的一些功能
Proxy 是 ES6 中新增的功能,它可以用来自定义对象中的操作。
比如:在vue 中拦截 - 预警,上报,扩展功能,增强对象
语法:
new Proxy(target , handler);
let obj = new Proxy (被代理的对象,对代理对象做什么操作);
handler{
set(){}------------------设置对象时的操作
get(){} ------------------获取对象时的操作
deleteProperty(){}------------------删除对象时的操作
has(){}------------------询问有没有这个对象时的操作
apply(){}------------------调用函数处理
.......
}
let obj = {
name :'ling'
}
//拦截,您访问了name
obj.name // ling
-------
let obj = { //未暴露给用户
name :'ling'
}
let newobj =new Proxy(obj,{ //代理obj
get(target,property){
console.log(target,property); //target操作对象obj,property 获取的对象 name/aaa
return target[property];
}
);
newobj.name;
newobj.aaa;
----------
let obj = {
name :'ling'
}
let newobj =new Proxy(obj,{
get(target,property){
console.log(`您访问了${property}属性`);
return target[property];
}
);
console.log(newobj.name);
------------
let obj = {
name :'ling'
}
let newobj =new Proxy(obj,{
get(target,property){
if(property in target){
console.log(`您访问了${property}属性`);
return target[property];
}else{
console.warn(`${property }不在此对象上`); //警告
throw new ReferenceError(`${property }不在此对象上`); //抛出一个错误
}
}
);
console.log(newobj.name);//您访问了name属性 ling
console.log(newobj.aaa);//aaa不在此对象上 aaa不在此对象上
apply() :
function fn(){
return '我是函数';
}
let newfn=new Proxy(fn,{
apply(){
return '函数吗?'
}
});
console。log(newfn()); //函数吗
Reflect
反射,拦截执行通过用反射。
function sum(){
return '我是函数';
}
let newSum=new Proxy(sum,{
apply(target,context,args){ //target 对象, args 参数数组, context
return Reflect.apply(...arguments)*2;
}
});
console。log(newSum(2,3)); // 10
Reflect.apply(调用的函数,this指向,参数数组)
alert(Math.cell(4.6)); //5
let res= Reflect.apply(Math.cell,null,[9.8]); //10
‘assign’ in Object ----> Reflect.has(Object,‘assign’);