第三章*****************************************************************************************
1.ES5:
ECMAScript: ECMA組織制定的JavaScript語言的國際標(biāo)準(zhǔn)匾旭,規(guī)定了JS語言的核心語法
ES5是ECMAScript的第五個版本(第四版過于復(fù)雜廢棄了)坦刀,IE8部分此版本
保護(hù)對象:
什么是:① 保護(hù)對象的屬性和屬性值始終有意義
? ? ? ?② 防止篡改對象的結(jié)構(gòu)
為什么:① 對象的屬性季希,默認(rèn)可隨意賦值
? ? ? ?② 對象可隨意添加耻警、刪除屬性
何時: 嚴(yán)格來說,今后所有對象涂屁,都要有自我保護(hù)的抵抗力
如何: 分為保護(hù)屬性和防篡改
保護(hù)屬性: 保護(hù)對屬性值的修改
對象屬性分為:
命名屬性: 可通過.直接訪問的屬性
? ? 分為:?數(shù)據(jù)屬性: 直接保存屬性值的屬性
? ? ? ? ? 訪問器屬性:?不直接存儲屬性值书在,僅提供對其他數(shù)據(jù)屬性的保護(hù)
內(nèi)部屬性: 無法通過.直接訪問的屬性
數(shù)據(jù)屬性的四大特性:
value:實(shí)際存儲屬性值
writable:true/false控制屬性是否可修改屬性值
enumerable:true/false控制屬性是否可被for in遍歷(false會跳過),僅控制遍歷拆又,無法控制用.訪問
configurable:true/false控制是否可刪除該屬性儒旬,控制是否可修改其它兩個特性
強(qiáng)調(diào): configurable經(jīng)常作為前兩個屬性的雙保險,且一旦設(shè)為false帖族,不可逆
獲取四大特性:
Object.getOwnPropertyDescriptor(obj,"屬性名")
設(shè)置1個屬性的四大特性:
Object.defineProperty(obj,"屬性名",{
? 要修改的特性:特性值,
? 要修改的特性:特性值,
? ... ...
})
問題: defineProperty一次只能修改一個屬性
解決: 同時修改多個屬性的特性:
Object.defineProperties(obj,{
? 屬性名:{ 要修改的特性 },
? 屬性名:{ 要修改的特性 },
? ... : ...
})
添加屬性: 可用defineProperty添加新屬性
? ? ? ? ? 只要defineProperty要修改的屬性不存在栈源,就會自動添加
強(qiáng)調(diào): 用defineProperty添加的新屬性,四大特性默認(rèn)值都為false
而用.添加的新屬性竖般,四大特性默認(rèn)值都為true
問題: 無法使用自定義邏輯保護(hù)屬性
解決:?訪問器屬性
_______________________________________________________________________________________________
訪問器屬性: 不直接存儲屬性值凉翻,僅提供對其他數(shù)據(jù)屬性的保護(hù)
何時: 只要使用自定義的規(guī)則保護(hù)屬性值
為什么: 數(shù)據(jù)屬性的四大特性,保護(hù)規(guī)則是固定的捻激,無法自定義
如何定義: 2步:
①定義一個隱藏的數(shù)據(jù)屬性,用于實(shí)際存儲屬性值
②再定義一個訪問器屬性前计,保護(hù)隱藏的數(shù)據(jù)屬性:
Object.defineProperty(obj,"屬性名",{/*或用defineProperties胞谭,不能通過直接量或.創(chuàng)建*/
?get(){? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*在試圖獲取屬性值時自動調(diào)用*/ ? ?
? ? return this.隱藏的數(shù)據(jù)屬性; ? ? ? ? ? /*返回受保護(hù)的數(shù)據(jù)屬性值*/
?},
?set(val){? ? ? ? ? /*在試圖修改屬性值時自動調(diào)用男杈,參數(shù)val會自動獲得要修改的新值*/
? ? if(...) ? ? ? ? ? ? ? ?/*驗(yàn)證val是否符合規(guī)則*/
? ? ? ... ? ? ? ? ? ? ? ? ?/*將val賦值給受保護(hù)的屬性*/
? ? else ... ? ? ? ? ? ? ? /*否則*/
? ? ? throw new Error ? ?? /*主動拋出錯誤*/
?},
enumerable:true, ? ? ? ? ?/*設(shè)置四大屬性*/
configurable:false
})
如何使用: 只要定義了訪問器屬性丈屹,就優(yōu)先使用訪問器屬性,而不用受保護(hù)的數(shù)據(jù)屬性
? ? ? ? ? 訪問器屬性的用法和普通屬性用法完全一樣
? ? ? ? ? 但是: 在取值時,自動調(diào)用get()
? ? ? ? ? ? ? ? 在賦值時旺垒,自動調(diào)用set()彩库,val會自動獲得要賦的新值
內(nèi)部屬性: 無法通過.直接訪問的隱藏屬性
? ? ? ? ? 比如: __proto__
_______________________________________________________________________________________________
防篡改: 阻止對對象結(jié)構(gòu)的修改
3個級別:
①防擴(kuò)展: 禁止添加新屬性
Object.preventExtensions(obj)
? 原理: 每個obj內(nèi)部都有一個隱藏屬性:?Extensible,默認(rèn)為true
? ? ? ? preventExtensions將obj的Extensible改為false
②密封: 在防擴(kuò)展的基礎(chǔ)上先蒋,進(jìn)一步禁止刪除現(xiàn)有屬性(兩個不要一起用)
Object.seal(obj)
? 原理: 將obj的Extensible改為false
? ? ? ? 將所有屬性的configurable都自動改為false
③ 凍結(jié): 在密封基礎(chǔ)上禁止修改一切屬性值(過于嚴(yán)格)
Object.freeze(obj)
? 原理: 修改obj的Extensible為false
? ? ? ? 將所有屬性的configurable都改為false
? ? ? ? 還將所有屬性的writable都改為false
_______________________________________________________________________________________________
Object.create(): 本質(zhì)上是創(chuàng)建一個新的子對象
什么是: 基于一個現(xiàn)有父對象骇钦,創(chuàng)建一個新的子對象繼承當(dāng)前父對象,并擴(kuò)展新屬性
何時: 今后如果沒有構(gòu)造函數(shù)的情況下竞漾,也想創(chuàng)建子對象
如何:
var child=Object.create(father,{ ? ?? /*若不用擴(kuò)展自有屬性眯搭,father后的內(nèi)容不必寫*/
? 自有屬性:{
? ? value:值,
? ? writable:true,
? ? enumerable:true,
? ? configurable:true,
? },
? ... : {
? ? ...
? }
});
強(qiáng)調(diào): 只要添加到對象中的屬性,四大特性默認(rèn)為false业岁,必須顯式寫為true
原理:① 創(chuàng)建一個空對象
? ? ?② 讓新對象自動繼承father
? ? ?③ 為新對象擴(kuò)展新的自有屬性
_______________________________________________________________________________________________
call/apply/bind:
共同:為了替換函數(shù)中不想要的this
何時: 只要函數(shù)中的this不是想要的 (函數(shù)不加括號鳞仙,只在call/apply/bind右邊加括號)
call和apply:
什么是:強(qiáng)行調(diào)用一個函數(shù)并臨時替換函數(shù)中的this為指定的新對象
call: ?要求傳入函數(shù)的參數(shù)必須單獨(dú)傳入,逗號分隔
第1個參數(shù)是要指定的this笔时,第2,3...個是要替換的參數(shù)
apply: 要求傳入函數(shù)的參數(shù)棍好,必須放入數(shù)組中整體傳入
? ? ?? apply可自動打散數(shù)組類型的參數(shù),單個傳入
第1個參數(shù)是要指定的this允耿,第2個參數(shù)是一個數(shù)組
bind: ?基于一個現(xiàn)有函數(shù)創(chuàng)建一個功能完全相同的新函數(shù)借笙,并永久綁定this為指定對象
? ? ? ?還可永久綁定部分固定的參數(shù)值
替換回調(diào)函數(shù)中的this時,都用bind
比如:?var newFun=fun.bind(obj) ? ?//接收新參數(shù)右犹,函數(shù)后添加
? ? ? ? ? ? ?newFun(參數(shù)1,...); ? ? ? ?? //調(diào)用函數(shù)
強(qiáng)調(diào): 被bind永久綁定的this提澎,不能再被call/apply臨時替換
_______________________________________________________________________________________________
數(shù)組API:
判斷: 判斷數(shù)組中的元素是否符合要求
返回值:bool(可判斷是否滿足條件)
①every: 判斷數(shù)組中所有元素是否都滿足要求
var?bool = arr.every(function(val,i,arr){? //回調(diào)函數(shù): 當(dāng)前元素值:val;當(dāng)前元素位置:i念链;arr:當(dāng)前數(shù)組
? return 判斷條件
});
②some: 判斷數(shù)組中是否包含滿足條件的元素
var bool = arr.some(function(val,i,arr){
? return 判斷條件
});
強(qiáng)調(diào):數(shù)組API的回調(diào)函數(shù)中this默認(rèn)->window盼忌,所以,不能用this指代當(dāng)前元素值,但可用如arr[i]或val
遍歷: 對數(shù)組中每個元素執(zhí)行相同的操作:
①forEach: 對原數(shù)組中每個元素執(zhí)行相同的操作
arr.forEach(function(val,i,arr){? ? //沒有返回值
? arr[i]=新值;? ? ? ? ? ? ? ? ? ? ? //對當(dāng)前元素執(zhí)行的操作掂墓,直接修改原數(shù)組谦纱,只能使用arr[i]
})
②map: 取出原數(shù)組中每個元素,執(zhí)行相同操作后君编,再放入新數(shù)組返回
var arr2 = arr1.map(function(val,i,arr){? ? ? ? //返回一個新數(shù)組
? return 對當(dāng)前元素操作后的新值(放入新數(shù)組中)? ? ? ? //不修改原數(shù)組跨嘉,使用arr[i]=..可修改原數(shù)組
})
過濾和匯總:
過濾: filter: 復(fù)制原數(shù)組中符合條件的元素,組成新數(shù)組
var subArr=arr.filter(function(val,i,arr){
? return 判斷條件? ? ? ? //篩選出arr中符合判斷條件(為true)的元素值吃嘿,放入新數(shù)組返回
})
匯總: reduce: 將數(shù)組中所有元素祠乃,統(tǒng)計出一個匯總結(jié)果
var r=arr.reduce(function(prev,val,i,arr){? ? ? ?//prev: 截止目前的臨時匯總值
? return prev+val
},startVal);? ? ? ? ? ? ? ? ? ? ? ? ? ?//startVal: 表示匯總開始的基數(shù),可不寫(默認(rèn)為0)
將arr數(shù)組中每個值累加后兑燥,求和
強(qiáng)調(diào): reduce不一定非要從0開始累加亮瓷,可從任意startVal(也可以是其它數(shù)組)開始累加
_______________________________________________________________________________________________
嚴(yán)格模式:
什么是: 比普通js運(yùn)行模式要求更嚴(yán)格的運(yùn)行機(jī)制
為什么: 解決普通js運(yùn)行模式中廣受詬病的缺陷
何時: 今后都要在嚴(yán)格模式下開發(fā)
① 新項(xiàng)目, 必須全部啟用嚴(yán)格模式
② 舊項(xiàng)目, 逐個函數(shù)向嚴(yán)格模式遷移
如何: 2種:
① 整個代碼段啟用嚴(yán)格模式:
在<script>標(biāo)簽或js文件的開頭加入:"use strict";
② 僅對單個函數(shù)啟用嚴(yán)格模式
僅在function內(nèi)降瞳,函數(shù)體的頂部加入:"use strict"嘱支;
要求:
1. 不允許對未聲明的變量賦值
2. 靜默失敗升級為錯誤
3. 不推薦使用arguments.callee來實(shí)現(xiàn)遞歸
_______________________________________________________________________________________________
2.ES6(框架廣泛采用蚓胸,又稱為ECMAScript 2015):
模板字符串: 對字符串拼接的簡化(2015年首次發(fā)布,IE Edge不支持)
何時: 如果字符串中包含需要動態(tài)執(zhí)行的表達(dá)式或回車換行時
如何:3件事
① 用``反引號(ESC鍵的正下方)包裹字符串
② 字符串中的變量和表達(dá)式都要放在${...}中
③ 模板字符串中支持: ?換行除师,變量沛膳,表達(dá)式(),注釋也會被解析
let:
1. 專門聲明僅在當(dāng)前塊中有效的局部變量
? 塊: js中只要一個{}就是一個代碼塊
? ? ? let聲明的變量汛聚,僅在{}內(nèi)有效锹安,不會被提前到{}外
2. 防止聲明提前現(xiàn)象
聲明提前: 在開始執(zhí)行程序前,引擎會將var聲明的變量和function聲明的函數(shù)贞岭,提前到"當(dāng)前作用域"頂部集中優(yōu)先創(chuàng)建八毯,再開始執(zhí)行程序 ? ? ? ? ?? /*但是賦值留在原地*/
何時:今后強(qiáng)烈建議用let代替var
強(qiáng)調(diào):let必須配套嚴(yán)格模式使用
_______________________________________________________________________________________________
箭頭函數(shù): 對所有回調(diào)函數(shù)的終極簡寫
何時: 今后,幾乎所有的回調(diào)函數(shù)瞄桨,都要用箭頭函數(shù)簡化
如何:
1.所有回調(diào)函數(shù)都可:去 function(參數(shù)) 改為 (參數(shù))=>
2.如果函數(shù)體只有一句話: 可省略{}
如果這一句話還是return话速,可省略return
3.如果只有一個參數(shù):可省略()
但是,如果沒有參數(shù),必須保留空()
特點(diǎn):箭頭函數(shù)可讓內(nèi)外this共用同一個對象————不再需要bind替換
特殊: 如果不希望內(nèi)外共用this芯侥,就不能用箭頭函數(shù)(或者用e.target -> 當(dāng)前單擊的元素對象)
比如事件處理函數(shù):
? elem.addEventListener("click",function(){ this -> 當(dāng)前單擊的元素對象,不共用 })
? elem.addEventListener("click",()=>{ 致使this -> 不是elem })
變通解決:
elem.addEventListener("click",e=>{ e.target->elem })? ? /*利用冒泡*/
特點(diǎn):
① 箭頭函數(shù)沒有this
② 箭頭函數(shù)沒有arguments
③ 不能通過 new 關(guān)鍵字調(diào)用
④ 沒有 new.target
⑤ 沒有原型
⑥ 沒有 super
_______________________________________________________________________________________________
for of: 簡化for循環(huán)遍歷:
何時: 直接獲得每個元素值時
如何:
for(var i=0;i<arr.length;i++){ arr[i] } ? ? ? /*arr[i]: 當(dāng)前元素*/
簡寫為:
for(var val of arr){ val } ? ? ? ? ? ?/*val: of會依次取出arr中每個元素的值泊交,保存到val*/
局限:
①只能遍歷索引數(shù)組和類數(shù)組對象,不能遍歷關(guān)聯(lián)數(shù)組和對象(只能用for in循環(huán)遍歷)
② 無法獲得下標(biāo)
③ 只能逐個遍歷所有柱查,不能控制循環(huán)的開始和結(jié)束以及步調(diào)
④按值傳遞: 如果數(shù)組中保存的是原始類型的值廓俭,修改val,不會影響數(shù)組元素(val是數(shù)組元素值的副本)
何時:僅遍歷元素值唉工,不關(guān)心下標(biāo)時研乒,才可用for of簡寫
_______________________________________________________________________________________________
class: 對 面向?qū)ο?的簡化
如何定義類型:
①用一個?class 類型名{}結(jié)構(gòu)包裹原來的 構(gòu)造函數(shù)和原型對象方法
②修改構(gòu)造函數(shù)的'function'為'constructor',其余保持不變
③可省略開頭的'類型.prototype'與方法名后的'=function'
直接定義在class中的函數(shù)直接量淋硝,會自動保存在當(dāng)前類型的原型對象中
定義父類:
class Flyer{
? constructor(fname,speed){
? ? this.fname=fname;
? ? this.speed=speed;
? }
? fly(){?}? ? ? ? //fly <=> Flyer.prototype.fly
? get 訪問器屬性名(){?return this.受保護(hù)的其他屬性?} ?? //添加訪問器屬性,在構(gòu)造函數(shù)的平級
? set 訪問器屬性名(val){
? ? if(條件) this.受保護(hù)的屬性=val
? ? else?報錯
? }
}
繼承: 不再設(shè)置Object.setPrototypeOf
①在'class 類型名'后添加'extends 父類型'名
② 在子類型構(gòu)造函數(shù)中不允許直接用call調(diào)用父類型構(gòu)造函數(shù)雹熬,可使用super(屬性參數(shù)值列表),不加this
子類:
class Plane extends Flyer{? ? ? ? ? ? ?//讓Plane繼承Flyer
? constructor(fname,speed,score){
? ? super(fname,speed);? //super:關(guān)鍵字,指父類型的構(gòu)造函數(shù)谣膳,自動將子類型的this傳入父類構(gòu)造函數(shù)中竿报,不允許用call
? ? this.score=score;
? }
? getScore(){ }
}
使用:
var obj = new Plane('fname',10,30)? ? //也可以new父類: var obj = new Flyer('fname',10)
obj.getScore()? ? ? ? //子類的方法
obj.fly()? ? ? ? ? ? ?//父類的方法