什么是ES6倒慧?
? ? ECMAScript 6.0 是繼ECMAScript 5.1 之后 JavaScript 語言的下一代標(biāo)準(zhǔn)摆出,發(fā)布在2015年6月掖举,它的目標(biāo)快骗,是使得JavaScript?語言可以用來編寫復(fù)雜的大型應(yīng)用程序,成為企業(yè)級開發(fā)語言塔次。
一方篮、let、const命令
let励负、const與var的區(qū)別藕溅?
a. let、const有塊級作用域的概念继榆,只要是定義的變量巾表,就是一個塊級作用域汁掠;var只有在函數(shù)中才有作用域;
b. let集币、const不允許重復(fù)聲明考阱;
c. let和var聲明的變量,都可以再修改鞠苟,而const定義的是常量乞榨,值是不可以修改的(對象除外,對象的屬性可以修改)
作用域的概念:
ES5有兩個作用域:全局和局部
ES6有了塊作用域的概念:塊作用域偶妖,通俗的理解姜凄,就是一個大括號,就是一個塊作用域趾访;
let聲明
案例:
使用let聲明的變量不可重復(fù)态秧,如下
????function test2(){
? ????? let a = 1;
? ????? let a = 2;
????}
????test2()
這樣聲明會報下圖錯誤:
這個意思是,a變量重復(fù)聲明了扼鞋;
const聲明
const定義時申鱼,必須要給初始值,否則下面再重新賦值會報錯云头,因為const定義的值不可以修改捐友;
const聲明的是常量,不可以修改(一般的值是不可以修改的昏滴,如果是對象格式是可以修改的谣殊,比如給已創(chuàng)建的對象中添加屬性是可以的)拂共,并且聲明時必須要賦值宜狐;
用途:為了防止意外修改變量,比如柑爸,引入庫名祥诽,組件名等
二厘熟、解構(gòu)賦值
什么是解構(gòu)賦值绳姨?
es6入門中的解釋:ES6 允許按照一定模式购撼,從數(shù)組和對象中提取值迂求,對變量進(jìn)行賦值毫玖,這被稱為解構(gòu);?
模式匹配:
?左邊和右邊要的數(shù)據(jù)格式要一樣十气;
解構(gòu)賦值的分類
這里重點理解:數(shù)組解構(gòu)與對象解構(gòu)
如果解構(gòu)賦值沒有找到對應(yīng)的賦值叶眉,這時默認(rèn)是undefined
數(shù)組解構(gòu)賦值:
使用場景
對象解構(gòu)賦值
在對象中的解構(gòu)賦值與數(shù)據(jù)的順序是無關(guān)的饱溢,比如:
let {a,b,c} = {b:10,a=11,c=12}
console.log(a); // 11?
上面的json格式解構(gòu)賦值時潘鲫,key名要與data數(shù)據(jù)中的key名一致状植;否則找不到對應(yīng)的數(shù)據(jù)振定,會顯示undefined;
解構(gòu)賦值給默認(rèn)值
語法:
let {time:12,id=0} = {}
用途:
比如在寫運動框架時,需要對傳過來的參數(shù)加默認(rèn)值;
ES5寫法:
function move(obj,json,options){
? ? options = options || {};
? ? options.time = options.time || 300;?
}
ES6解構(gòu)賦值寫法:
function move(obj,josn,{time=300}={}){
}
三、正則擴(kuò)展
新增的特性
ES5與ES6寫法對比
ES6增加U和Y的修飾符
U 修飾符
四瘤旨、字符擴(kuò)展
字符串新增特性
字符串中新增了幾個方法,是es7預(yù)案的,需要下載補丁才會支持贺辰,否則會報錯,所以在當(dāng)前項目下,安裝babel-polyfill庫,如圖:
安裝成功后,需要在index.js入口文件引入這個庫歹鱼,就可以進(jìn)行使用了掺涛,如圖:
a).字符Unicode表示法
b).codPointAt()使用方法
c).includes(str)、startsWith(str)、endsWith(str)方法的使用
d).repeat(number)方法的使用
e).模版字符串
f).padStart(s1,s2)拧粪、padEnd(s1,s2)方法濒析,ES7提案的API,很重要!U肿ぁ骏啰!
j).標(biāo)簽?zāi)0?/h4>
String.raw
五.數(shù)值擴(kuò)展
數(shù)值處理新增特性:
????1.新增方法 壁熄;2.方法調(diào)整
二進(jìn)制與八進(jìn)制
Number.isFinite()
Number.isInteger()
Number.isSafeInteger()方仿、Number.MAX_SAFE_INTEGER此洲、Number.MIN_SAFE_INTEGER
Math.trunc()
Math.sign()
Math.cbrt()
六.數(shù)組擴(kuò)展
ES5方法回顧:
1.遍歷數(shù)組的方法
說明:通過遍歷數(shù)組可以得到下標(biāo)和下標(biāo)對應(yīng)的值汁汗;
forEach()斤程、map()扁藕、filter()、every()、some()
forEach()使用方法
let arr =[1,3,4,5,6,7]
let newArr = arr.forEach(function(item,index){
? ? //可以得到值和下標(biāo)
? ? console.log(item,index)
});
console.log(newArr) // undefined
forEach的返回值為 undefined
map()使用方法
let arr =[1,3,4]
let newArr = arr.map(function(item,index){
? ?? //可以得到值和下標(biāo)? ?
? ? ?console.log(item,index)
});
console.log(newArr) // undefined
map的返回值為[ undefined , undefined , undefined]
map會把返回的值放到一個新的數(shù)組中,默認(rèn)return 是undefined瞬痘,所以上面數(shù)組有幾項察绷,就返回幾個undefined喘沿。
所以通過這一點,就可以把循環(huán)得到的值念赶,進(jìn)行計算翰灾,通過return 再返回到新數(shù)組中致开;
具體實例如下:
let arr =[1,3,4]
let newArr = arr.map(function(item,index){? ???
//將循環(huán)的每一項乘以2后糜芳,再返回到新數(shù)組中
? return item * 2;
});
console.log(newArr);//[2,6,8] 得到的是計算后的新數(shù)組
filter()使用方法
filter也可以循環(huán)數(shù)組,得到下標(biāo)和值,但是更多作為過濾使用;具體如下:
//過濾出小于3的數(shù)
let arr = [1,2,3,4];
let newArr = arr.filter(function(item,index){
? ? return item < 3;
});
//當(dāng)不寫return 時返回的是一個空數(shù)組
console.log(newArr); // [] ?得到一個空數(shù)組
filter的返回值,返回的是回調(diào)函數(shù)中為true的那一項
如果上案例,return item < 3 ,這時返回的是小于3的數(shù);
ES6新方法:
數(shù)組復(fù)制的方法:
1) for循環(huán);
2) Array.from(arr);//數(shù)組新增from()方法
3) let arr2 = [...arr]质况;//展開運算符
Array.of()
Array.from()
fill()
keys()臼朗、values()誊涯、entries()
copyWithin(s1,s2,s3)
find()取逾、findIndex()
includes(num)
七.函數(shù)擴(kuò)展
ES5中參數(shù)是沒有默認(rèn)值的琉用;
函數(shù)參數(shù)默認(rèn)值
根據(jù)以上es5中默認(rèn)值的情況來看晶丘,如果參數(shù)是0,會被讀成false,導(dǎo)致運算出現(xiàn)問題本股;
所以es6擴(kuò)展了直接給默認(rèn)值的寫法案站,如下:
關(guān)于函數(shù)作用域
rest參數(shù)(...)
擴(kuò)展運算符(...)
1.數(shù)組的擴(kuò)展:將一個數(shù)組轉(zhuǎn)為逗號分隔的參數(shù)序列炒刁;
說明:是把數(shù)組中的值里伯,以逗號分隔脖镀,把每個值展開强窖;不是轉(zhuǎn)成字符串;
例:找到數(shù)組中的最大值
let arr =[1,5,7,9,3,55];
//原始做法:
console.log(Math.max(1,5,7,9,3,55));//55
//使用擴(kuò)展運算符的做法:
console.log(Math.max(...arr));//55
2.對象的擴(kuò)展:用于取出對象中所有可遍歷的屬性,拷到當(dāng)前對象中;
例:
let obj1 ={a:1,b:2};
let obj2 = {
????...obj1 密末, ?
? ? c:3 ? //這里也可以寫自己的屬性
//obj1 中有a屬性握爷,那么如果obj2中再寫一個a屬于跛璧,就會把obj1中已擴(kuò)展過來的a屬于的值改變
? ? a:66 ?//這樣再打印obj2的a屬性就是66
};?
說明以上這樣的做法,相當(dāng)于淺拷貝追城;
箭頭函數(shù)
注意事項:
????1.箭頭函數(shù)中沒有arguments對象,如果要用燥撞,可以用rest參數(shù)代替座柱;
????2.不能當(dāng)作構(gòu)造函數(shù),不可以使用new命令物舒,否則會拋出錯誤(Fn is not constructor)色洞;
????3.不能當(dāng)作Generator函數(shù)使用;
this指向
es5普通函數(shù)中的this
????1. this表示誰調(diào)用的就是誰冠胯;
????2. 默認(rèn)情況火诸,在嚴(yán)格模式下返回是undefined,非嚴(yán)格模式下是window荠察;
????3. 可以用call,apply,bind改變this的指向置蜀;
es6函數(shù)中的this
????1. 箭頭函數(shù)體內(nèi)沒有自己的this對象,所以在使用的時候悉盆,
? ? ? ? 其內(nèi)部的this就是定義時所在環(huán)境的對象盯荤,而不是使用時所在環(huán)境的對象;
????2. 不可以用call,apply,bind改變this的指向焕盟;
????3. 箭頭函數(shù)中沒有arguments對象秋秤,如果要用,可以用rest參數(shù)代替脚翘;
普通函數(shù)與箭頭函數(shù)this指向示例
尾調(diào)用
八.對象擴(kuò)展
*這里的擴(kuò)展指的Object對象灼卢,不是指類生成的對象
簡潔表示法
屬性表達(dá)式
新增API
Object.is(str1,str2)
判斷兩個字符串是否相等
str1是否與str2相等,這個判斷與es5中的 '===' 判斷是一樣的
console.log(Object.is('a','a'));//true
//數(shù)組也是引用類型堰怨,所以這里是false
console.log(Object.is([],[]));//false
Object.assign(str1,str2):拷貝
str1:要拷貝到這個對象上;
str2:把str2對象拷貝到str1對象上蛇摸;
注意點:
????1. 這種拷貝的屬性是有限制的备图,屬于淺拷貝;
????2. 只拷貝對象自身上的屬性赶袄,如果對象有繼承和不可枚舉的屬性揽涮,是不可以拷貝的;
? ? 3. 靜態(tài)方法饿肺,返回值是str1對象蒋困;
console.log(Object.assign({a:'a'},{b:'b'}));//{a: "a", b: "b"}
Object.entries(obj)
獲取對象的key和value的值,傳入要拷貝的對象
let test ={a:123,b:456};
for(let [key,value] of Object.entries(test)){
????console.log( [key,value] );//["a", 123]? ["b", 456]
}
擴(kuò)展運算符
let arr =[1,2,3,4];
console.log(...arr);//1 2 3 4
//下面這個是ES7提的預(yù)案敬辣,暫時沒有支持方法
let {a,b,...c}={a:'test',b:'kill',c:'ddd',d:'ccc'};//這樣寫頁面會報語法錯誤
Symbol數(shù)據(jù)類型
Symbol的概念:提供獨一無二的值雪标,聲名的值永遠(yuǎn)不會重復(fù)和相等零院;
聲明方法
方法一:這種是直接聲名Symbol值,值一定不會相等村刨;
leta1 =Symbol();
leta2 =Symbol();
console.log(a1===a2);//false
方法二:使用Symbol.for(str)方法聲名告抄;
str:是Symbol中的key值,有這個key值嵌牺,for方法在聲名這個獨一無二的變量時打洼,會先檢查key值是不是在全局注冊過,如果注冊過返回注冊時候的值逆粹,如果沒有注冊過募疮,就會聲成一個獨一無二的值;
這種聲名的好處:參數(shù)中是key名僻弹,相當(dāng)于給Symbol起了個名字阿浓,方便之后的調(diào)用;
let ?a3 = Symbol.for('a3');
let ?a4 = Symbol.for('a3');
true 就表示 a3 和 a4 的值是相等的奢方,因為 a4 的Symbol的key值是已經(jīng)注冊過了搔扁,聲名 a3 時注冊的,
所以 a3 的這個key值蟋字,存在的變量就是 a3,所以兩者比較是true
console.log( a3 === a4 );//true?
Symbol的作用
獲取Symbol的屬性
九.數(shù)據(jù)結(jié)構(gòu)
Set()
定義方法
????1> 通過new方式來創(chuàng)建 new Set()
????2> new Set(arr) 可以向Set中加入一個數(shù)組結(jié)構(gòu)的數(shù)據(jù)稿蹲,會自動變成Set類型的數(shù)據(jù)
Set 中的一些操作方法
????add(str):向Set中添加成員;
????delete(str):刪除Set中str元素鹊奖,返回刪除后的Set集合
????clear():清空所有Set中的元素苛聘,返回清空后的Set集合
????has(str):檢查Set中有沒有str元素,返回boolean忠聚,有true,沒有false
????size屬性:獲取Set的成員數(shù)量(長度)设哗;
Set的特性
Set中的元素是不可以重復(fù)的,如果元素中有重復(fù)两蟀,會只顯示不重復(fù)的元素网梢,重復(fù)元素會自動去掉,利用這個特性可以對數(shù)組進(jìn)行去重赂毯。
let ?arr =[1,1,1,2,2,3,3];
let ?list =newSet(arr);
console.log(list);//{1, 2, 3}
在去重的時候需要注意战虏,Set只去重同數(shù)據(jù)類型的數(shù)據(jù),數(shù)組中不同數(shù)據(jù)類型是不會強(qiáng)制類型轉(zhuǎn)換的党涕;
let ?arr2 =[1,'1',2,2,3,3];
let ?list2 =newSet(arr2);
//通過打印出的元素可以看出沒有類型轉(zhuǎn)換
console.log(list2);// {1, "1", 2, 3}
Set實例的遍歷(讀取里面的元素)
使用keys()烦感、values()、entries()膛堤、forEach手趣、直接使用let of來遍歷里面的元素
WeakSet()
WeakSet與Set的區(qū)別:
????1. 支持的數(shù)據(jù)類型不一樣,WeakSet的元素只能是對象(boolean,String等這些都不可以)肥荔;
????2. WeakSet中的對象是一個弱引用绿渣,不會去檢測這個對象有沒有在其它地方用過朝群, 不會跟GC掛勾,就是說怯晕,在WeakSet中添加了一個對象潜圃, ? ? ? ? ? 這個對象不是值拷過來,只是地址的引用舟茶,而且也不會去檢測這個地址是不是返回GC回收了谭期;
????3. 有些Set的屬性和方法WeakSet是沒有的(clear()、size屬性吧凉、不能遍歷)隧出;
WeakSet方法:
????1. add(val):添加成員
????2. delete(val):刪除成員
????3. has(val):判斷val成員是否存在,返回boolean類型阀捅,true存在胀瞪,反之false
使用案例:
Map()對象
Map的方法:
????1. set(key,value):添加元素,key,value格式的
????2. get(key):根據(jù)key名饲鄙,找對應(yīng)的value值
????3. delete(key):刪除key名對應(yīng)的值
????4. clear():清空map
????5. size屬性:獲取map中的成員數(shù)量
Map的循環(huán):
? ? 不能使用for ..in凄诞,沒有效果;需要使用for ...of來循環(huán)
例如:
let map = new Map();
map.set('a','aaa');
map.set('b','bbb');
for(let key of map){
? ? console.log(key);//a,aaa, ?b,bbb
}
注意:這里of 后面直接寫map 得到的是key和value忍级,因為這里默認(rèn)是map.entries()帆谍;
也可以是只循環(huán)出key 或者 value
寫法如下:
for(let key of map.keys()){ ? //只循環(huán)key
????console.log(key);//a ?b
}
for(let value of map.values()){? ?????//只循環(huán)value
????console.log(value);//aaa ?bbb
}
Map的兩種寫法:
WeakMap()
WeakMap與Map的區(qū)別:
????1. 支持的數(shù)據(jù)類型不一樣,WeakSet的元素只能是對象(boolean,String等這些都不可以)轴咱;
????2. WeakSet中的對象是一個弱引用汛蝙,不會去檢測這個對象有沒有在其它地方用過,不會跟GC掛勾朴肺,就是說窖剑,在WeakSet中添加了一個對象,
? ? ? ? 這個對象不是值拷過來戈稿,只是地址的引用西土,而且也不會去檢測這個地址是不是返回GC回收了;
????3. 有些Set的屬性和方法WeakSet是沒有的(clear()鞍盗、size屬性需了、不能遍歷);
WeakMap的方法:
????1. add(val):添加成員
????2. delete(val):刪除成員
????3. has(val):判斷val成員是否存在橡疼,返回boolean類型援所,true存在庐舟,反之false
let weakMap = new WeakMap();
let o ={};
weakMap.set(0,123);
console.log(weakMap.get(o));//123
數(shù)據(jù)結(jié)構(gòu)對比
說明:在es5中欣除,經(jīng)常使用的數(shù)據(jù)結(jié)構(gòu)就是Array和object來存儲;es6中挪略,新增了Map和Set历帚,那么什么時候使用這些類似滔岳,下面就做一個對比;
數(shù)據(jù)結(jié)構(gòu)橫向?qū)Ρ韧炖危銎酌海椋那莅危瑒h
map和array的對比
增加成員
查詢成員
修改成員
刪除成員
set和array的對比
增加成員
查詢成員
修改成員
刪除成員
Map,Set與Object對比
增加成員
查詢成員
修改成員
刪除成員
通過幾上對比刘离,提一個建議性的總結(jié),純屬個人看法:
能使用map睹栖,不使用數(shù)組硫惕,如果對數(shù)據(jù)要求高,數(shù)據(jù)結(jié)構(gòu)要求存儲的唯一性野来,考慮set恼除,放棄使用object;
Proxy與Reflect
Proxy:代理的意思曼氛,作用就是相當(dāng)于代理商豁辉,連接了用戶與對象最中間的那一層;
Reflect:反射Object的作用舀患;
這兩種的方法是一模一樣的徽级,只是生成對象的形式不一樣;這里只演示Proxy的方法构舟;
Proxy是通過new的方式灰追;Reflect是直接調(diào)用,如Reflect.get這樣的寫法狗超;
Proxy對象說明:
原始數(shù)據(jù)對象弹澎,通過Proxy對象,對原始數(shù)據(jù)進(jìn)行了代理努咐,代理后苦蒿,會生成一個新的對象,如下案例monitor渗稍,之后對這個數(shù)據(jù)的操作佩迟,都是對monitor對象進(jìn)行操作,最終Proxy都會將操作后的數(shù)據(jù)竿屹,返回給obj报强。可以理解成拱燃,Proxy對obj所有屬性有一個讀取的作用秉溉,可以說是攔截,也可以是代理;
案例:
let obj ={ //原始數(shù)據(jù)召嘶,可以看做是供應(yīng)商
? ? time:'2017-12-27',
????name:'net',
????_r:123
};
/*
????Proxy(obj,{})
????obj:要代理的數(shù)據(jù)對象父晶;{}:這里面實現(xiàn)這些代理的方法
*/
????let monitor =new Proxy(obj,{
????/*
????????get(target,key):攔截(代理)對象屬性的讀取
????????target:就是obj這個原始數(shù)據(jù)中所有的數(shù)據(jù);
????????key:數(shù)據(jù)對象中的key名弄跌,下面的monitor調(diào)用哪個屬性甲喝,
????????這個key就是哪個屬性名
*/
? ? get(target,key){
????//將讀取到的2017換成2018
? ? ? ? return target[key].replace('2017','2018');
????},
/*
????????set(target,key,value):攔截對象設(shè)置屬性
????????target:原始數(shù)據(jù)對象; key:要修改的屬性铛只;value:要修改的值埠胖;
*/
? ? set(target,key,value){
????//這里舉例只改key值是name的數(shù)據(jù),其它的值不可以修改
? ? ? ? if(key==='name'){//當(dāng)key是name時
????//就讓name的值,等于value
? ? ? ? ? ? return target[key] =value;
????}else{
????????//否則返回之前的值
? ? ? ? ? ? return target[key];
????}
},
/*
????has(target,key):判斷當(dāng)前對象中淳玩,是否有某個屬性
????攔截key in object操作
*/
? ? has(target,key){
????//要只暴露name屬性,就是說通過 key in object方法押袍,
????//只能判斷到name屬性是存在的,其它都查不到
? ? ? ? if(key==='name'){
????????????return target[key];
????????}else{
????????????return false;
????????}
????},
/*
????????deleteProperty(target,key):攔截delete
????????target:原始數(shù)據(jù)對象凯肋;key:數(shù)據(jù)中的key值
*/
? ? deleteProperty(target,key){
????//這里攔截下劃線開頭的屬性谊惭,就可以刪除,其它的全部不可以刪除
? ? ? ? if(key.indexOf('_') >-1){
????????????delete target[key];
? ? ? ? ? ? ?return true
? ? ? ? }else{
????????????return target[key];
????????}
????},
/*
????????ownKeys(target):
????????攔截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames侮东,
????????要獲取的屬性名圈盔。保護(hù)指定屬性不被以上這些方法獲取到
*/
? ? ownKeys(target){
????//通過Object.keys把原始key者拿出來,然后再過濾
? ? ? ? return Object.keys(target).filter(item=>item !='time')
? ? }
});
//通過打印可以看出悄雅,Proxy代理了原始數(shù)據(jù)驱敲,并做出修改,這不會影響到原始數(shù)據(jù)宽闲;
????console.log(monitor.time);//2018-12-27
????console.log(obj.time);//2017-12-27
????monitor.time='2019';
????console.log(monitor.time);//2018-12-27? 并沒有修改成2019
????monitor.name='hello';
????console.log(monitor.name);//hello? 這里就改變了众眨,說明代理的set方法起了作用
????console.log('name' in monitor);//true 查詢到有這個屬性
????console.log('time' in monitor);//false 沒查詢到有這個屬性,因為限制了查詢
? ? delete monitor.time;
????console.log(monitor.time);//發(fā)現(xiàn)獲取到了容诬,說明沒有被刪除
????delete monitor._r;
????console.log(monitor);?//{time: "2017-12-27", name: "hello"} 發(fā)現(xiàn)被刪除了娩梨,攔截是有作用的
????console.log(Object.keys(monitor));// ["name", "_r"]? 這里沒有time,time被攔截保持了
總結(jié):通過用戶拿到的對象览徒,和原始對象狈定,之間是不可以直接操作的,要通過代理习蓬,在代理的層面纽什,可以通過不同的業(yè)務(wù)邏輯來做相應(yīng)的處理;比如怎么讀躲叼,怎么寫芦缰;
實際應(yīng)用場景:
通過Proxy和Reflect來實現(xiàn)業(yè)務(wù)解耦的校驗?zāi)K;比較常用的應(yīng)用場景枫慷;
function validator(target,validator){
????return new Proxy(target,{
????????//這里就是進(jìn)入到代理了
? ? ? ? _validator :validator,
????set(target,key,value,proxy){//這里是Proxy對象的set方法
????//判斷當(dāng)前目標(biāo)對象让蕾,有沒有Key值
? ? ? ? ? ? if(target.hasOwnProperty(key)){
? ? ? ? ? ? ? ? ? ? let va =this._validator[key];//把這個條件,這個條件是封裝好的驗證方法包斑,拿出來
????????????if(!!va(value)){//如果這個是存在,就把值拿出來
????????????//這個時候涕俗,就把代理返回到真實數(shù)據(jù)中
? ? ? ? ? ? ? ? ? ? ? ? return Reflect.set(target,key,value,proxy)
? ? ? ? ? ? ? ? ? ? }else{//不存在,就拋出異常
? ? ? ? ? ? ? ? ? ? ? ? throw Error(`不能設(shè)置${key}到${value}`)
? ? ? ? ? ? ? ? ? ? }
????????????????}else{//如果沒有就拋出異常
????????????????????//不存在就把key顯示出去
? ? ? ? ? ? ? ????????? throw Error(`${key} 不存在`)
? ? ? ? ? ????? }
????????}
????????})
}
????const? personValidator = {
????????//name校驗的方法神帅,如果name是string類型再姑,就允許代理修改,否則不允許
? ? ????????name(val){
????????return typeof? val==='string'
? ? },
????//age必須是數(shù)字找御,并且大于18
? ? ????age(val){
????????????return typeof? val ==='number' &&val >18;
????????}
????}
????????//創(chuàng)建一個Person對象
????????class Person{
????????????constructor(name,age){//構(gòu)造函數(shù)
? ? ? ????? this.name =name;
????????????this.age =age;
????????????????//返回的是一個代理
? ? ? ????? return validator(this,personValidator)
? ? ????}
????}
? ? //下面就可以實際驗證了
????const person =new Person('lilei',30);
????console.log(person)
十.類與對象
類的基本定義與對象的生成
類的繼承
繼承傳遞參數(shù)
父類構(gòu)造函數(shù)中的參數(shù)元镀,如何傳遞到子類參數(shù)中,并且子類如何替換繼承過來的父類參數(shù)霎桅;
使用super()來實現(xiàn)子類向父類傳遞參數(shù)栖疑;
????super():不傳參數(shù)時,表示子類全部使用父類的所有默認(rèn)參數(shù)和值滔驶;
????super(str1...):傳參數(shù)時遇革,表示要替換父類的參數(shù),需要替換幾個揭糕,就傳幾個萝快;
關(guān)于super特別要注意:在繼承關(guān)系中,子類在傳遞參數(shù)中著角,使用了super揪漩,那么super一定要放在子類
構(gòu)造函數(shù)中的第一行,否則會報錯吏口;
getter與setter
靜態(tài)方法
靜態(tài)屬性
十一.Promise
什么是promise:實際上就是一個對象奄容,主要是用來傳遞異步操作的數(shù)據(jù);
什么是異步:比如产徊,a和b兩個函數(shù)昂勒,a執(zhí)行完再執(zhí)行b,在程序上舟铜,這個步驟叁怪,有兩種方式去執(zhí)行:
? ? ? ? ? ? ? ? ? ? ? 一種是通過回調(diào),一種是事件觸發(fā)的方式深滚;
promise的作用:解決異步操作的問題奕谭;
es5的異步寫法
ES6的promise寫法
連續(xù)串行的promise執(zhí)行
關(guān)于串行的問題
關(guān)于串行過程,如果在中間某一步出錯了痴荐,怎么捕獲這個錯誤血柳?
使用promise提供的catch來捕獲。
promise兩個重要場景
Promise.all()的使用場景
使用promise.all的方法生兆,把多個promise的實例难捌,當(dāng)做是一個promise實例膝宁;
promise.all([p1,p2,p3]):這里傳的是一個數(shù)組格式,數(shù)組傳多個promise實例根吁;
注意员淫,當(dāng)里面多個promise實例狀態(tài)全部發(fā)生改變的時候,才會觸發(fā)promise.all击敌,返回的新的promise對象介返,后面才可以使用then等一些方法。
場景一:所有圖片加載完再添加到頁面中
Promise.race()的使用場景
????????有三個圖片沃斤,在三個不同的位置圣蝎,這個頁面需要加載其中一張圖片,但不知道這三個圖片哪個返回比較快衡瓶,也不關(guān)心哪個比較快徘公,但是知道這三個圖片的加載來源,加載出一個來源就可以哮针;所以就是說关面,先到先得,哪個先加載出來十厢,就顯示哪個缭裆;
Promise.race():格式,寫法和promise.all一樣寿烟;
race里面的promise實例澈驼,哪一個先改變了,就會觸發(fā)race的實例筛武,剩下的就不管了
十二.Iterator和for...of循環(huán)
Iterator接口可以看成是一個遍歷器缝其;
Iterator接口的作用:實現(xiàn)不同數(shù)據(jù)類型之間,統(tǒng)一讀取里面的數(shù)據(jù)徘六;
for...of循環(huán)的過程内边,就是在背后不斷的調(diào)用Iterator接口來達(dá)到這種形式;不同的數(shù)據(jù)結(jié)構(gòu)通過for...of統(tǒng)一的這種形式待锈,來達(dá)到讀取不同的數(shù)據(jù)結(jié)構(gòu)的目標(biāo)漠其,但是背后的Iterator接口是不同的;
數(shù)組循環(huán)中for..of與for ..in的區(qū)別:for..of循環(huán)的是數(shù)組中的每一項竿音,for ..in循環(huán)的是索引和屎;
Iterator接口寫法
簡單的Iterator接口寫法:[Symbol.iterator]()以方法的形式表示;
接口都有一個next():這個方法是用來查看是否還有數(shù)據(jù)春瞬,返回的是對象類型柴信,固定的有兩個屬性,value和done宽气,value返回的是數(shù)據(jù)中的值随常,done是boolean類型潜沦,true表示下面還有數(shù)據(jù),false表示沒有數(shù)據(jù)了绪氛。
Iterator自定義
Iterator接口也可以用來自定義;
for...of不可以循環(huán)對象唆鸡,可以通過Iterator接口來實現(xiàn)。
十三.Generator
Generator:異步編程的解決文案枣察,也可以說是一個狀態(tài)機(jī)争占;可以遍歷,語法就是一個函數(shù)询件;
異步編程有:回調(diào),promise唆樊,這個Generator相對于這兩個比較高級一些宛琅;
基本定義
Generator返回的就是一個Iterator接口
寫法,就是一個function后面緊跟著一個星號逗旁,function*(){}
以上得出嘿辟,Generator調(diào)用next()會一直找到函數(shù)中的return ,就會結(jié)果查找,done返回true片效;
上面的return 返回的是undefined所以找到這里就會結(jié)果查找红伦;
yield
yield語句本身沒有返回值,或者每次返回undefined淀衣;
next
next是可以帶參數(shù)的昙读,參數(shù)會給上一個yield的值;
實際應(yīng)用
作為狀態(tài)機(jī)的演示
說明:比如有a b c三種狀態(tài)描述一個事物膨桥,這個事物只存在三種狀態(tài)a b c蛮浑,永遠(yuǎn)沒有第四種狀態(tài);generator處理這種狀態(tài)最適合只嚣;
async與await
async與await:這兩個是generator的語法糖沮稚,就是把generator的function* (){}中的星號去掉,在function前面加async册舞,函數(shù)中的yield改成await蕴掏。其它的使用方法全部一樣;想執(zhí)行以下代碼,需要加一個babel的插件
實際使用場景
場景一调鲸,抽獎
前端如何做抽獎次數(shù)的限制荐类,當(dāng)抽獎次數(shù)用完后,提示用戶不可以再抽獎笙什。
重點是怎么計算當(dāng)前還有多少次蓝翰,之前的做法是設(shè)置一個全局變量,來保存當(dāng)前次數(shù),這樣非常不安全贯钩,如果對方知道這個次數(shù)的變量募狂,會隨意修改办素,這樣就無法攔截了;而且盡量不要把數(shù)據(jù)存放在全局變量中祸穷,影響頁面性能性穿;
下面使用generator來實現(xiàn);
場景二雷滚,長輪詢
長輪詢需曾,如何說服務(wù)端某一個數(shù)據(jù)定期變化,前端需要定期去取這個變化的數(shù)據(jù)祈远;
因為http是無狀態(tài)的鏈接呆万,取經(jīng)常變化的狀態(tài),可以使用websocket和長輪詢车份;
因為這個websocket兼容性不是很好谋减,所以一般經(jīng)常使用的就是長輪詢的方法;
之前的長輪詢是通過定時器扫沼,不斷的去取狀態(tài)出爹,使用generator可以讓頁面的代碼變的更優(yōu)雅。把相關(guān)業(yè)務(wù)區(qū)分開缎除;
十四.Decorator(修飾器)
概念:修飾器是一個函數(shù)严就,用來修改類的行為,修改類的行為器罐,可以理解為擴(kuò)展類的功能梢为,這個修飾器的修改范圍,只能是類的轰坊;
需要裝一個支持Decorator語法的包:npm install babel-plugin-transform-decorators-legacy ?--save-dev
安裝后抖誉,要在.babelrc文件中加一個插件:"plugins":["transform-decorators-legacy"]
修飾器的函數(shù)
函數(shù)中三個參數(shù)說明:
????target:要修改的類本身
????name:屬性名
????descriptor:屬性的描述對象
現(xiàn)實中實用案例
日志系統(tǒng)(埋點):這里是把埋點的相關(guān)邏輯放到了修飾器里面,業(yè)務(wù)相關(guān)邏輯代碼寫到一個class中衰倦;
這樣寫的好處:
1.把埋點系統(tǒng)抽離出來袒炉,成為一個可復(fù)用的模塊;如后續(xù)發(fā)現(xiàn)變化樊零,直接改埋點的相關(guān)代碼我磁,不需要動class中的代碼;
2.業(yè)務(wù)代碼也簡潔了驻襟,好維護(hù)了夺艰;
總結(jié)就是,使用修飾器沉衣,可以使代碼更有復(fù)用性郁副、簡潔、好維護(hù)M阆啊4婊选拔疚!
十五.Module模塊化
個人理解來講,一個一個的js文件就是一個個的模塊既荚,模塊中的變量代碼相互引用稚失。
模塊化要實現(xiàn)的目標(biāo),要解決功能單一恰聘;一個模塊一個功能句各;
引用方法
首先在js文件中,把需要暴露的變量導(dǎo)出晴叨,如圖:
導(dǎo)出方法一:
導(dǎo)出方法二:
在當(dāng)前文件中凿宾,導(dǎo)出后,使用import引入
引入方法:
1兼蕊、將導(dǎo)出的所有變量都寫在大括號中
? ? ? import {a,test,hello} from "./class/lesson18"
2初厚、大括號里,需要哪個寫哪個 ??
? ? ??import {a} from "./class/lesson18"
3遍略、如果遇到導(dǎo)出的變量非常多惧所,有好幾十甚至幾百個可以使用 import * as name from url 這種方式
? ? ? ?'*':表示文件中所有導(dǎo)出的變量骤坐;
? ? ? ?'name':是一個別名绪杏,另起一個名字,所有的變量都會存到這個對象中纽绍;
????????import * as test18 from "./class/lesson18"? ? // test18就是一個別名蕾久,這個對象中存放了所有的變量名