ES6学习笔记
参考书在线阅读:《ES6标准入门(第三版)》
let
1 | let a; |
- 变量不能重复声明。(var可以重复声明)
1
2let a=1;
//let a=2;//× - 块级作用域
ES5中的三种作用域:全局,函数,eval(严格模式)1
2
3
4{
let doge='wangwang';
}
console.log(doge);//取不到,但是var取得到 - 不存在变量提升
1
2
3
4
5
6
7
8
9console.log(song);
var song='海上日记';
//相当于:
var song;
console.log(song);//undefined
var song='海上日记';
console.log(song);//使用let则会报错
let song='一程山路'; - 不影响作用域链以for循环为例:
1
2
3
4
5
6
7{
let master='miaomiao';
function playWithCat(){
console.log(master);
}
playWithCat();//可以读取
}结构为: for(单次表达式1;条件表达式2;末尾循环体3){中间循环体;} 相当于:1
2
3
4
5for(let i=0;i<items.length;i++){
items[i].onclick=function(){
items[i].style.background='pink';
}
}i为全局变量,所以循环结束时,i=item.length,但此时items[i]取不到值。 将var改为let可解决问题:1
2
3
4
5
6
7
8
9{
var i=0;
}
{
var i=1;
}
{
var i=2;
}这样数组的每一项都能得到修改。 所以以后for循环尽量用let声明初始值。1
2
3
4
5
6
7
8
9{
let i=0;
}
{
let i=1;
}
{
let i=2;
}
const
- 一定要赋初始值
- 一般常量使用大写(不强制)
- 常量值不能修改
- 块级作用域
- 对于数组和对象的元素修改,不算作对常量的修改,不会报错
1
2const ANI=['Aria','Digimon','OnePiece'];
ANI.push('IScream');//可以修改
变量的解构赋值
ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值。
- 数组的解构
1
2
3
4
5
6const F4=['佐助','罗夏','路飞','白龙'];
let [sasuke,rorschach,luffy,haku]=F4;
console.log(sasuke);//佐助
console.log(rorschach);//罗夏
console.log(luffy);//路飞
console.log(haku);//白龙 - 对象的解构
1
2
3
4
5
6
7
8
9
10
11
12const rorschach={
name:'罗夏',
age:28,
money:function(){
console.log('我有很多钱');
}
};
let {name, age, money}=rorschach;
console.log(name);//罗夏
console.log(age);//28
console.log(money);//function...
money();//我有很多钱
模板字符串
ES6引入了新的声明字符串的方式[``]反引号。
- 声明
1
2let str=`我也是一个字符串哦`;
console.log(str, typeof str);//我也是一个字符串哦 string - 内容中可以直接出现换行符
普通的引号无法换行,只能用加号+拼接。1
2
3
4
5
6let str=`
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
</ul>`; - 变量拼接
1
2
3let lovest='水星领航员';
let out=`我最喜欢的番剧是${lovest}`;
console.log(out);//我最喜欢的番剧是水星领航员
对象的简化写法
ES6允许在大括号里直接写入变量和函数,作为对象的属性和方法。书写更简洁。
1 | let name='长门'; |
箭头函数
let fn=(a,b)=>{...};
- this是静态的,this始终指向函数声明时所在作用域下的this的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18function a(){
console.log(this.hh);
}
let b=()=>{
console.log(this.hh);
}
window.hh='window的属性';
const bianliang={
hh:'bianliang的属性'
}
//直接调用:this都是指向window
a();//window的属性
b();//window的属性
//call方法调用:可以改变函数内部this的值
a.call(bianliang);//bianliang的属性
b.call(bianliang);//window的属性 (箭头函数的this不被改变) - 不能作为构造函数实例化对象
1
2
3
4
5
6let Artist=(name,album)=>{
this.name=name;
this.album=album;
}
let hikaru=new Artist('宇多田光','First Love');
console.log(hikaru);//报错 - 不能使用arguments(用于保存实参)变量
1
2
3
4let fn=()=>{
console.log(arguments);
}
fn(1,2,3);//报错 - 箭头函数的简写
(1)省略小括号,当形参有且只有一个的时候(2)省略花括号,当代码体只有一条语句的时候,此时return必须省略,且语句的执行结果就是函数的返回值1
2
3
4let add=n=>{
return n+n;
}
console.log(add(9));1
2let add=n=>n*n;
console.log(add(9)); - 应用箭头函数适合与this无关的回调:定时器,数组的方法回调。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//需求:点击div 2s后变成粉色
let ad=document.getElementById('ad');
//普通函数的写法:
ad.addEventListener('click',function(){
let _this=this;//this的常见命名:_this, that, self
setTimeOut(function(){
_this.style.background='pink';
},2000);
});
//箭头函数的写法:
ad.addEventListener('click',function(){
setTimeOut(()=>{
this.style.background='pink';//这里的this指代的就是该函数外层作用域的事件源ad
},2000);
});
箭头函数不适合与this有关的回调:事件回调,对象的方法。
函数参数的默认值设置
ES6允许给函数参数赋初始值。
- 形参初始值:具有默认值的参数,一般位置靠后(潜规则)。
1
2
3
4
5function add(a,b,c=10){
return a+b+c;
}
let result=add(1,2);
console.log(result);//13 - 与解构赋值结合使用
1
2
3
4
5
6
7
8
9function fn({a,b,c='hhh'}){
console.log(a);
console.log(b);
console.log(c);
}
fn({
a:'111',
b:'222'
});
rest
ES6引入rest参数,用于获取函数的实参,用来代替arguments。
1 | //ES5获取实参的方式: |
如有多个参数,rest参数必须要放到最后。
扩展运算符[…]
扩展运算符能将数组转换为逗号分隔的参数序列。
1 | const girls=['花花','泡泡','毛毛']; |
- 数组的合并
1
2
3
4
5
6
7
8const girls=['Alicia','Akira','Athena'];
const girls2=['Akari','Aika','Alice'];
//ES5:
const ariaSpirit1=girls.concat(girls2);
console.log(ariaSpirit1);//['Alicia','Akira','Athena','Akari','Aika','Alice']
//ES6:
const ariaSpirit2=[...girls,...girls2];
console.log(ariaSpirit2);//['Alicia','Akira','Athena','Akari','Aika','Alice'] - 数组的克隆
1
2
3const zm=['A','B','C'];
const zm2=[...zm];
console.log(zm2);//['A','B','C'] 浅拷贝 - 将伪数组转为真正的数组
1
2
3const div=document.querrySelectorAll('div');
const divArr=[...div];
console.log(divArr);
Symbol
ES6引进的新的原始数据类型,表示独一无二的值,是一种类似字符串的数据类型。
特点
(1)Symbol的值是唯一的,用来解决命名冲突的问题;
(2)Symbol的值不能与其它数据进行运算、拼接、对比;
(3)Symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。1
2
3
4
5
6
7
8
9
10
11
12
13let s =Symbol();
console.log(s,typeof s);//Symbol() "symbol"
let s2=Symbol();
let s3=Symbol();
console.log(s2===s3);//false
//symbol好比身份证,参数是姓名
let s4=Symbol.for('One Piece');
console.log(s4, typeof s4);//Symbol(One Piece) "symbol"
let s5=Symbol.for('One Piece');
console.log(s4===s5);//true目前所学的前端数据类型:
USONB you are so niubility
u undefined
s string symbol
o object
n null number
b boolean使用:给对象添加属性和方法
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//写法一:
let game={
name:'扫雷'
};
let methods={
up:Symbol(),
down:Symbol()
};
game[methods.up]=function(){
console.log(1);
};
game[methods.down]=function(){
console.log(2);
}
//写法二:
let youxi={
name:'连连看',
[Symbol('say')]:function(){
console.log(3);
},
[Symbol('run')]:function(){
console.log(4);
}
}(不太清楚该功能的具体使用场景,和ES5相比有什么优势…)
11个Symbol内置值(属性)
Symbol内置值 用法 Symbol.hasInstance 当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法 Symbol.isConcatSpreadable 对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat() 时, 是否可以展开。 Symbol.species 创建衍生对象时,会使用该属性 Symbol.match 当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。 Symbol.replace 当该对象被 str.replace(myObject) 方法调用时,会返回该方法的返回值。 Symbol.search 当该对象被 str.search (myObject) 方法调用时,会返回该方法的返回值。 Symbol.split 当该对象被 str.split(myObject) 方法调用时,会返回该方法的返回值。 Symbol.iterator 对象进行 for…of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器 Symbol.toPrimitive 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。 Symbol. toStringTag 在该对象上面调用 toString 方法时,返回该方法的返回值 Symbol. unscopables 该对象指定了使用 with 关键字时,哪些属性会被 with 环境排除。
迭代器
迭代器(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署iterator接口,就可以完成遍历操作。
- ES6创造了一种新的遍历命令for…of循环,iterator接口主要供for…of消费。
- 原生具备iterator接口的数据(可用for…of遍历):
(1)Array
(2)Arguments
(3)Set
(4)Map
(5)String
(6)TypedArray
(7)NodeList - 工作原理
(1)创建一个指针对象,指向当前数据结构的起始位置;
(2)第一次调用对象的next方法,指针自动指向数据结构的第一个成员;
(3)接下来不断调用next方法,指针一致往后移动,直到指向最后一个成员。 - 应用:自定义遍历数据
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
27const std={
name:'Sam',
score:[
60,
80,
90
],
[Symbol.iterator](){
let index=0;
let _this=this;
return{
next:function(){
if(index<_this.score.length){
const result= {value:_this.score[index],done:false};
index++;
return result;
}else{
return {value:undefined,done:true}
}
}
};
}
}
//对对象的遍历
for(let v of std){
console.log(v);
}
生成器
生成器其实就是一个特殊的函数。
用来进行异步编程。
ES5使用纯回调函数、node、fs、ajax、mongodb进行异步编程。
- 使用生成器函数
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
32function * gen(){
console.log('hello');
}
let iterator=gen();
console.log(iterator);//直接调用显示函数,函数本身不执行
//在生成器函数可以出现yield语句:yield相当于函数代码的分隔符
function * gen2(){
//三个分隔符产生四块代码,由next方法执行
console.log(111);
yield '哈哈';
console.log(222);
yield '呵呵';
console.log(333);
yield '嘿嘿';
console.log(444);
}
let iterator=gen2();
iterator.next();//111 {value: '哈哈', done: false}
//在上面的代码执行完后再执行这个:
iterator.next();
iterator.next();//222 333 {value: '嘿嘿', done: false}
//在上面的代码执行完后再执行这个:
iterator.next();//444 {value: undefined, done: true}
//遇到yield就暂停,调用next就继续
//遍历的调用方法:
for(let v of gen2()){
console.log(v);
}//111 哈哈 222 呵呵 333 嘿嘿 444 - 生成器函数参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14function * gen(arg){
//三个分隔符产生四块代码,由next方法执行
console.log(arg);
let one= yield '哈哈';
console.log(one);
let two= yield '呵呵';
console.log(two);
let three= yield '嘿嘿';
console.log(three);
}
let iterator=gen('haha');
iterator.next();//haha {value: '哈哈', done: false}
//执行完上面再执行下面:
iterator.next('hehe');//hehe {value: '呵呵', done: false} - 实例一
1秒后输出111,2秒后输出222,三秒后输出333。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//ES5的写法:回调地狱
setTimeout(()=>{
consol.log(111);
setTimeout(()=>{
consol.log(222);
setTimeout(()=>{
console.log(333);
},3000);
},2000);
},1000);
//使用生成器函数:
function one(){
setTimeout(()=>{
console.log(111);
iterator.next();
},1000);
}
function two(){
setTimeout(()=>{
console.log(222);
iterator.next();
},2000);
}
function three(){
setTimeout(()=>{
console.log(333);
iterator.next();
},3000);
}
function * gen(){
yield one();
yield two();
yield three();
}
let iterator=gen();
iterator.next();
Set
1 | let s= new Set();//集合 |
- 数组去重:
let result=[...new Set(arr)];
- 交集:
let result=[...new Set(arr)].filter(item=>{new Set(arr2).has(item)});
(filter函数体内如果是true就留下重复的,false则去掉) - 并集:
let result=[...new Set([...arr,...arr2])];
- 差集:
let result=[...new Set(arr)].filter(item=>!(new Set(arr2).has(item)))
Map
ES6提供了Map数据结构,它类似对象,也是键值对集合。但是键的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
Map也实现了iterator接口,所以可以使用“扩展运算符”和“for…of”进行遍历。new Map()
- 属性和方法
(1)size:返回Map的元素个数
(2)set:增加一个新元素,返回当前Map
(3)get:返回键名对象的键值
(4)has:检测Map中是否包含某元素,返回boolean
(5)clear:清空集合,返回undefined
(6)delete:删除某个元素
Proxy
Proxy字面翻译为“代理”,从书面理论上来讲,是ES6中全新创建的一种构造函数,用于拦截对象属性的访问、赋值、函数调用的默认事件,从而进行更改。和后端语言的get/set写法类似,更改原来的取值赋值操作,通过一个自定义的过程得到新的结果,并返回出去。
那么这种技术是如何在软件中应用的呢?
比如变量赋值前的校验、记录对象取值赋值的操作日志、监控对象的性能等等,可以增强代码的安全性。var proxy = new Proxy(target, handler);
先创建一个Proxy对象,该对象为ES6原生提供,Proxy对象有两个参数:第一个是目标对象,第二个对象用来放置拦截方法。
1 | let my_obj={}; |
Reflect
- ES6提供的新的API,将原本部署在Object上的方法复制到Reflect上(今后Object上的方法会逐渐废除),并做了优化,且未来新增的Object上的方法只部署在Reflect对象上。
- Reflect对象方法与Proxy对象方法一一对应。
- Reflect共有13个静态方法:(具体参数使用时再查)
· (1)Reflect.get
. (2)Reflect.set
· (3)Reflect.apply
· (4)Reflect.construct (提供一种不写new的构造函数写法)
· (5)Reflect.defineProperty
· (6)Reflect.deleteProperty
· (7)Reflect.has (in运算符)
· (8)Reflect.ownKeys (=Object.getOwnPropertyNames+Object.getOwnPropertySymbols, 返回字符串数组)
· (9)Reflect.isExtensible
· (10)Reflect.preventExtensions
· (11)Reflect.getOwnPropertyDescriptor
· (12)Reflect.getPrototypeOf (读取对象的__proto__属性)
· (13)Reflect.setPrototypeOf
Promise
Promise,译为“承诺”(只有异步操作能改变Promise对象的状态:Pending->Fulfilled(Resolved) or Pending->Rejected(Resolved),且改变之后不会再改变)。
Promise是ES6引入的异步编程的新解决方案。语法上是一个构造函数,用来封装异步操作可以获取其成功或失败的结果。
Promise可以将异步操作以同步操作的流程表达出来。
缺点:一旦执行,无法中途取消。
- Promise构造函数:Promise(excutor){}可以用于封装读取文件;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17const p=new Promise(function(resolve,reject){
//将异步方法放在Promise实例内
setTimeout(function(){
//let data='haha';
//resolve(data);
let err='fail';
reject(err);
},1000);
});
//只要写了.then,实例内的异步方法就会给出回调结果到then内函数里
p.then(function(value){
//resolve走这里(then的第一个参数函数)
console.log(value);
},function(reason){
//reject走这里(then的第二个参数函数)
console.error(reason);
});
可以用于封装ajax请求。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20const p=new Promise((resolve,reject)=>{
const xhr=new XMLHttpRequest();
xhr.open("GET","https://api.apiopen.top/getJoke");
xhr.send();
xhr.onreadystatechange=function(){
if(xhr.readyState===4){
//判断状态响应码:200-299
if(xhr.status>=200&&xhr.status<300){
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
});
p.then(function(value){
console.log(value);
},function(reason){
console.error(reason);
}); - Promise.prototype.then(fun)
用于指定回调,为成功和失败结果作处理,对象状态由回调函数的执行结果决定。
如果回调函数中返回的结果是非promise类型的属性,状态为成功,则返回值为对象的成功的值;
如果回调函数中返回的结果是promise类型的,外面的promise返回的结果是什么,内层的promise状态就是什么,也可以抛出错误。new p1.then(return new p2...)
then方法的返回的结果是一个Promise对象:所以可以链式调用,p.then(value=>{}).then(value=>{})...
避免回调地狱。 - Promise.prototype.catch(fun)
用来指定promise对象失败的回调。p.catch(function(){...})
catch写法优于在.then的第二个参数中定义reject函数,即只要写成:catch方法返回的也是一个Promise对象,因此也可以继续链式调用(如果是链式catch,下一个方法会捕获上一个方法中的错误)。1
2
3var p=new Promise(function(resolve,reject){...})
.then(function(data){...})
.catch(function(err){...}); - Promise.all([…])
用于将多个Promise实例包装成一个Promise实例。
All Fulfilled, Fulfilled.
One Rejected, Rejected.(交集)1
2
3var p=Promise.all([p1,p2,p3])
.then(function(data){...})//第一个Rejected的进入这里
.catch(function(err){...}); - Promise.race([…])
One Resolved/Rejected, Resolved/Rejected.(并集) - Promise.resolve(obj)
转为Promise对象
· (1) obj为一个Promise对象:返回obj
· (2) obj为一个普通对象,有then方法:返回Promise对象,并立即执行then方法
· (3) obj不是对象,或没有then方法:返回Promise对象,从生成时就是Resolved状态,没有异步操作
· (4) Promise.resolve()直接执行,不带参数:返回Promise对象,在本轮事件循环结束时置为Resolved状态 - Promise.reject(msg/obj)
· (1) 参数为字符串:返回Promise对象,立即执行后状态为Rejected,msg为reject的理由
· (2) 参数为含有then方法的对象:返回Promise对象,catch得到的参数为obj的then中reject的方法 - 自己部署一个done方法(jquery已提供)done会捕捉到任何错误,并向全局抛出。
1
2
3
4
5
6
7
8
9
10
11Promise.prototype.done=function(onFulfilled, onRejected){
this.then(onFulfilled, onRejected)
.catch(function(reason){
setTimeout(()=>{throw reason},0);
});
};
AsyncFun()
.then(f1)
.catch(r1)
.then(f2)
.done();//放在回调链的尾端
done不返回Promise对象,所以不能再接catch。 - 自己部署一个finally方法
不管Promise对象最后状态如何都会执行的操作。finally并不是最后一环,done才是。1
2
3
4
5
6
7
8
9
10Promise.prototype.finally=function(callback){
let p=this.comstructor;
return this.then(
value=>p.resolve(callback()).then(()=>value),
reason=>p.resolve(callback()).then(()=>{throw reason})
);
};
AsyncFun()
.then(f1)
.finally(f2);//f2是一个回调函数,一定会执行 - Promise.try(fun)
不用区分fun是同步函数还是异步函数,如果是同步函数则同步执行,如果是异步函数则异步执行。1
2
3Promise.try(fun)
.then(...)
.catch(...)
Iterator(遍历器) 和 for…of
- Iterator是一种接口,可用于遍历操作。
- Iterator创造指针对象,调用指针的next方法,指向下一个成员。
- Iterator接口部署在Symbol.iterator属性上,原生具备Iterator接口的数据结构:Array,Map,Set,String,TypedArray,函数的arguments对象,NodeList对象。
- 具有Iterator接口的数据结构,都可以用for…of循环。
class 类
ES6的class可以只看作是一个语法糖,只是让对象的写法更清晰,更像面向对象的编程的语法。
声明类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//ES5:
function Phone(brand,price){//构造函数
this.brand=brand;
this.price=price;
}
Phone.prototype.call=function(){//添加方法
console.log('打电话');
}
let huawei=new Phone('华为',5999);//实例化
huawei.call();
//ES6:
class Phone{
constructor(brand,price){
this.brand=brand;
this.price=price;
}
call(){//不支持ES5的对象完整形式
console.log('打电话');
}
}
let iphonex=new Phone('Apple',10000);constructor()方法就算没写,JS也会自动添加。
静态成员
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//ES5:
function Phone{...}
Phone.name='手机';//往函数对象上添加属性和方法
Phone.change=function(){...};
Phone.prototype.size='5.5inch';
let nokia=new Phone();
console.log(nokia.name);//undefined 静态成员无法继承
//实例对象身上没有构造函数对象身上的属性
console.log(nokia.size);//5.5inch 原型上的属性是有的
//ES6:
class Phone{
static name='手机';//静态成员,实例化对象无法获取
static change(){...};
}对象继承
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
38
39
40
41
42
43//ES5:
function Phone(brand,price){
this.brand=brand;
this.price=price;
}
Phone.prototype.call=function(){
console.log('打电话');
}
function SmartPhone(brand,price,color,size){
Phone.call(this,brand,price);
this.color=color;
this.size=size;
}
//设置子级构造函数的原型
SmartPhone.prototype=new Phone;
SmartPhone.prototype.constructor=SmartPhone;
//声明子类的方法
SmartPhone.prototype.photo=function(){...}
SmartPhone.prototype.playGame=function(){...}
const chuizi=new SmartPhone('锤子',2499,'黑色','5.5inch');
console.log(chuizi);//brand√ price√ color√ size√ __proto__:Phone photo√ playGame√ __ptoto__: call√
//ES6:
class Phone{
constructor(brand,price){//构造方法
this.brand=brand;
this.price=price;
}
call(){
console.log('打电话');
}
}
class SmartPhone extends Phone{//构造方法
constructor(brand,price,color,size){
super(brand,price);//super是父类的constructor,包含了call
this.color=color;
this.size=size;
}
photo(){...}
playGame(){...}
}
const xiaomi=new SmartPhone('小米',799,'黑色','4.7inch');
console.log(xiaomi);//子类属性+方法和父类属性+方法都在对象继承二:子类对父类方法的重写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21//ES6:
class Phone{
constructor(brand,price){
this.brand=brand;
this.price=price;
}
call(){
console.log('打电话');
}
}
class SmartPhone extends Phone{
constructor(brand,price,color,size){
super(brand,price);
this.color=color;
this.size=size;
}
photo(){...}
playGame(){...}
call(){...}//父类包含这个方法,但是内容和父类不同
}
const xiaomi=new SmartPhone('小米',799,'黑色','4.7inch');get和set
1
2
3
4
5
6
7
8
9
10
11class Phone{
get price(){
console.log('价格属性被读取了');
return '999';
}
set price(value){
console.log('价格属性被修改了');
}
let s=new Phone();//实例化一个对象
s.price='free';
}
数值扩展
- Number.EPSILON:js的最小精度
Number.EPSILON ≈ 2.220446049250313080808472633361816E-16
用于判断精度:if Math.abs(a-b)<Number.EPSILON
- 二进制、八进制、十六进制
let b=0b1010;//=十进制的10 二进制用0b开头
let o=0o777;//=十进制的511 八进制用0o开头
let x=0xff;//=十进制的255 十六进制用0x开头 - Number.isFinite(n):检测一个数是否为有限数
1
2Number.isFinite(100/0);//false
Number.isFinite(Infinite);//false - Number.isNaN(n):检测一个变量是否为NaN(not a number)
- Number.parseInt(str):字符串转整数 Number.parseFloat(str):字符串转小数
1
2Number.parseInt('5211314love');//5211314 截断
Number.parseFloat('3.1415926率');//3.1415926 - Number.isInteger(n):判断一个数是否为整数
- Math.trunc(n):将数字的小数部分抹掉
- Math.sign(n):判断一个数为正数、负数、还是零
1
2
3Math.sign(-100);//-1
Math.sign(0);//0
Math.sign(33);//1
对象方法扩展
- Object.is(a,b):判断两个值是否完全相等,一般情况下相当于===
1
2Object.is(NaN,NaN);//true
NaN===NaN;//false - Object.assign(a,b):对象的合并
1
2
3
4
5
6
7
8
9
10
11
12const s1={
a:1,
b:2,
c:3
};
const s2={
a:11,
b:22,
d:4
}
console.log(Object.assign(s1,s2));//{a:11,b:22,c:3,d:4}
//结果:对象合并,相同属性以后一个为主 - Object.getPrototypeOf:获取原型对象 Object.setPrototypeOf:设置原型对象
1
2
3
4const a={name:'aaa'};
const b={age:18};
Object.setPrototypeOf(a,b);//将b作为原型对象给a的__proto__属性
//不建议使用,一般在Object.create时就定义好原型
模块化
模块化:将一个大的程序文件,拆分成多个小的文件,然后组合起来。
- 优点:防止命名冲突,代码复用,高维护性
- 已有的模块化产品:CommonJS=>NodeJS、Browserify,AMD=>requireJS,CMD=>seaJS
- 模块化语法:
export:用于规定模块的对外接口
import:用于输入其他模块提供的接口
(1)通用的导入方式1
2
3
4
5
6
7
8
9
10
11
12
13
14//分别暴露
export let a=1;
export function b(){...}
//统一暴露
c:1;
function d(){...}
export {c,d};
//默认暴露
export default{
e:1,
f:function(){...}
}(2)解构赋值形式1
2
3
4
5<script type="module">
import * as m1 from './src/js/m1.js';
m1.default.f();
</script>1
2
3
4
5
6
7
8
9
10
11
12
13//m1.js
export let a=1;
export function b(){...}
//m2.js
export let a=2;
export let c='cc';
//m3.js
export default{
let a=3;
function d(){...}
}(3)简便形式,针对默认暴露1
2
3
4
5<script type="module">
import {a,b} from './src/js/m1.js';//a,b可以直接使用
import {a as a1,c} from './src/js/m2.js';//重命名重名变量
import {default as m3} from './src/js/m3.js';//默认暴露必须要重命名
</script>(4)使用模块化方式二1
2
3<script type="module">
import m3 from './src/js/m3.js';
</script>1
2
3
4//main.js
import * as m1 from './src/js/m1.js';
import * as m2 from './src/js/m2.js';
import * as m3 from './src/js/m3.js';1
<script src="./src/js/main.js" type="module"></script>
- babel对ES6模块化代码转换
有的浏览器不一定支持在script标签里增加src属性的方式,所以用 babel 做一个转换,可以将比较新的ES6语法转为有些浏览器只能识别的ES5语法。
(1)安装工具 babel-cli, babel-preset-env, browserify(webpack)
(2)npx babel src/js -d dist/js
(3)打包 npx browserify dist/js/app.js -o dist/bundle.js - ES6模块化引入NPM包
1
2//先 npm i jquery 安装包
import $ from 'jquery';//原来的写法:const $ =require('jquery');
ES7新特性
- Array.prototypr.includes
1
2
3const z=['a','b','c','d'];
console.log(z.includes('a'));//true
//与之相比,indexOf返回的是数字下标,includes更方便 - 指数操作符 “ ** ”
1
2console.log(2 ** 10);//1024
console.log(Math.pow(2,10));//1024
ES8新特性
- async和await
async和await两种语法结合可以让异步代码像同步代码一样。
(1)async函数
- async函数的返回值为promise对象
- promise对象的结果由async函数执行的返回值决定(2)await表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15async function fn(){
//return 'aaa';
//1.只要函数本身返回的不是一个promise对象,则async就能返回一个成功(resolved)的Promise对象
//throw new Error('出错啦');
//2.抛出错误,返回的就是一个失败的Promise对象
//3.返回的结果是一个Promise对象
return new Promise((resolve,reject)=>{
//resolve('成功的数据');
//reject('失败');
});
}
const result=fn();
console.log(result);//与函数本身返回的结果一致 - await必须写在async函数中
- await右侧的表达式一般为promise对象
- await返回的是promise成功的值
- await的promise失败了,就会抛出异常,需要通过try…catch捕获处理(3)例子:async与await结合读取文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13const p=new Promise((resolve,reject)=>{
//resolve("成功的值");
reject("失败了");
});
async function main(){
try{
let result=await p;
console.log(result);
}catch(e){
console.log(e);
}
}
main();(4)async与await结合发送Ajax请求1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24const fs=require('fs');
function readMd1(){
return new Promise((resolve,reject)=>{
fs.readFile("./xxx1.md",(err,data)=>{
if(err) reject(err);//如果失败
resolve(data);//如果成功
})
})
}
function readMd2(){
return new Promise((resolve,reject)=>{
fs.readFile("./xxx2.md",(err,data)=>{
if(err) reject(err);//如果失败
resolve(data);//如果成功
})
})
}
async function main(){
let result1 = await readMd1();
let result2 = await readMd2();
console.log(result1.toString());
console.log(result2.toString());
}
main();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
26function sendAJAX(url){
return new Promise((resolve,reject)=>{
const x=new XMLHttpRequest();
x.open('GET',url);
x.send();
x.onreadystatechange=function(){
if(x.readyState===4){
if(x.status>=200&&x.status<300){
resolve(x.resopnse);
}else{
reject(x.status);
}
}
}
})
}
//promise then方法测试:
const result_p = sendAJAX("https://api.apiopen.top/getJoke").then(value=>{
console.log(value);
},reson=>{});
//async与await测试:
async function main(){
let result =await sendAJAX("https://api.apiopen.top/getJoke");
consol.log(result);
}
main();
Object.values()
返回一个给定对象的所有可枚举属性值的数组。Object.entries()
返回一个给定对象自身可遍历属性[key,value]的数组。1
2
3
4
5
6
7
8
9const obj={
a:'aaa',
b:['b1','b2','b3'],
c:[333,444]
};
console.log(Object.keys(obj));//['a','b','c']
console.log(Object.values(obj));//['aaa',['b1','b2','b3'],[333,444]]
console.log(Object.entries(obj));//[0:['a','aaa'],1:['b',[...]],2:['c',[...]]]
console.log(new Map(Object.entries(obj)));//{['a','aaa'],['b',[...]],['c',[...]]}Object.getOwnPropertyDescriptors()
返回指定对象所有自身属性的描述对象。
configurable
enumerable
ES9新特性
- 对象的rest参数和spread扩展运算符
1
2
3
4
5
6
7
8
9
10
11
12function fn({a,b,...c}){...}
fn({
a:'aaa',
b:123,
c1:'cc1',
c2:'cc2',
c3:333
})
const x1={x11:'content1'};
const x2={x22:'content2'};
console.log({...x1,...x2});//{x11:'content1',x22:'content2'} - 正则扩展-命名捕获分组
1
2
3
4let str='<a href="https://www.baidu.com">百度</a>';
const reg=/<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result=reg.exec(str);
consolelog(result);//可以获取result.groups.url, result.groups.text - 正则扩展-反向断言
- 正则扩展-dotAll模式
ES10新特性
- Object.fromEntries
Object.entries可以将对象转为二维数组,Object.fromEntries可以将二维数组转为对象(键值对) - 字符串方法扩展:trimStart 和 trimEnd
指定清除字符串左侧空格和右侧空格 - 数组方法扩展:flat 和 flatMap
flat:将多维数组转为低维数组,从外往内展开,不加参数默认展开一层,参数为深度。
flatMap:两个操作的结合,先map,后flat。 - Symbol.prototype.description
获取Symbol的字符串描述。1
2let s=Symbol('name');
consol.log(s.description);//name
ES11新特性
- 私有属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class Person{
//公有属性
name;
//私有属性
#age;
#weight;
//初始化:构造方法
constructor(name,age,weight){
this.name=name;
this.#age=age;
this.#weight=weight;
}
intro(){
console.log(this.name);
console.log(this.#age);
console.log(this.#weight);
}
}
const girl=new Person('小红',18,'45kg');
//console.log(girl.#age);//报错
girl.intro();//可以获取私有属性 - Promise.allSettled
1
2
3
4const p1=new Promise(...);
const p2=new Promise(...);
const result=Promise.allSettled([p1,p2]);//只要有一个成功就显示成功
const result2=Promise.all([p1,p2]);//全都成功才不报错 - String.prototype.matchAll
适合数据的批量提取。1
2
3const str=`...`;
const reg=/.../;
const result=str.matchAll(reg); - 可选链操作符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16function fn(x){
//const con=config && config.db && config.db.host;
const con=x?.name?.a;
}
// fn({
// name:{
// a:'aaa',
// b:'bbb'
// },
// school:{
// c:'ccc',
// d:'ddd'
// }
// })
fn();
//即使fn没有传入用到的参数,也不会报错,免去了层层判断 - 动态import
ES6的模块化本身是静态的。1
2
3
4
5
6const btn=document.getElementById('btn');
btn.onclick=function(){
import('./hello.js').then(module=>{
module.hello();
})
} - BigInt(大整型)数据类型
1
2
3
4
5
6
7let n=521n;
//整型可以转成大整型
let n2=123;
console.log(BigInt(n2));//123n
//应用于大数值运算
let max=Number.MAX_SAFE_INTEGER;
console.log(BigInt(max)+BigInt(1)); - 绝对全局对象globalThis
指向window对象。
编程风格(迷你知识点)
- 建议不再使用var命令
- let和const之间优先使用const
- 静态字符串使用单引号,动态字符串使用反引号,不再使用双引号
- 添加属性用Object.assign(obj,{name:’aa’});
End.🐧