這周因為朋友結(jié)婚幫忙的緣故,學(xué)習(xí)的內(nèi)容明顯下降了不少瓶籽。所以,等明天開始埂材,得需要恢復(fù)之前每天學(xué)習(xí)的強度塑顺。
本周的學(xué)習(xí)共分為3塊:
- ES6基礎(chǔ)學(xué)習(xí)與深入;
- Vue源碼閱讀楞遏;
- 前端進(jìn)階班的預(yù)習(xí)茬暇;
下面我們按照上面模塊一起去看一下本周我到底獲得了哪些收貨。
1.ES6學(xué)習(xí)
閱讀完成《深入理解ES6》的第三章寡喝。第三章主要講述的是函數(shù)的ES6新特性糙俗。
我們都知道ES6是ES5的加強與補充,是為了解決ES5中某些遺留問題而提出的新的解決方案或者加強预鬓,所以順著這個思路巧骚,我就去做了這樣的筆記。
1.1 ES6函數(shù)新特性
在ES6中格二,針對函數(shù)劈彪,補充了如下的一些特性:
- 參數(shù)默認(rèn)值
- 使用不具名函數(shù)
- 函數(shù)構(gòu)造器增強
- 擴展運算符
- 函數(shù)的雙重用途
- 塊級函數(shù)
- 箭頭函數(shù)
- 尾調(diào)用優(yōu)化
1.1.1 參數(shù)默認(rèn)值
傳統(tǒng)的ES5設(shè)置函數(shù)默認(rèn)值需要逐個對參數(shù)進(jìn)行設(shè)置,所以代碼量非常多顶猜,而且對于JS這種不限制函數(shù)參數(shù)的行為其擴展性也很差沧奴。所以ES6在ES5的基礎(chǔ)上增加了參數(shù)默認(rèn)值的特效,其語法如下:
function demo(url, timeout = 2000 , fn = function()
{console.log('do it')
})
值得注意的是长窄,我們可以向參數(shù)傳遞Undefined值來使用默認(rèn)的參數(shù)值滔吠,以上面函數(shù)為例,
demo('http://www.baidu.com',undefined,fn)
這樣就可以繼續(xù)使用第二個參數(shù)的默認(rèn)值了挠日。
初次之外疮绷,還涉及到了2個比較“冷門的問題”:
- ES6參數(shù)默認(rèn)值是如何影響argument對象;
- 參數(shù)默認(rèn)值的暫時性死區(qū)嚣潜;
1.1.2 使用不具名函數(shù)
ES5的不具名的arguments對象在實際使用過程中會有很多的限制冬骚。在書中,就通過underscorejs庫中Pick函數(shù)的講解來說出arguments的不足懂算。
// 復(fù)制特定對象的特定屬性
function pick(object) {
let result = Object.create(null);
// 從第二個參數(shù)開始處理
for (let i = 1, len = arguments.length; i < len; i++) {
result[arguments[i]] = object[arguments[i]];
}
return result;
}
- 雖然該函數(shù)能處理多個函數(shù)只冻,但是在函數(shù)的表現(xiàn)上則完全看不出;
- 函數(shù)的第一個參數(shù)是選中的目標(biāo)對象计技,從第二個開始才是需要復(fù)制的屬性喜德。
因此ES6引入了剩余參數(shù)這個概念,使用剩余函數(shù)對上述函數(shù)進(jìn)行改寫酸役,則清晰和優(yōu)雅不少住诸。
function pick(object, ...keys) {
let result = Object.create(null);
for (let i = 0, len = keys.length; i < len; i++) {
result[keys[i]] = object[keys[i]];
}
return result;
}
通過引入剩余參數(shù),我們就可以知道函數(shù)可以處理多余的函數(shù)涣澡。并且這與包含所有參數(shù)的arguements不同贱呐,我們可以單獨對剩余函數(shù)進(jìn)行處理。當(dāng)然剩余函數(shù)也有剩余的不足入桂,主要有以下兩點:
- 剩余參數(shù)必須要放在最后面奄薇;
- 剩余參數(shù)放在setter函數(shù)中不可用,會報語法錯誤馁蒂。
1.1.3 函數(shù)構(gòu)造器
作者聲稱,函數(shù)默認(rèn)值加上剩余函數(shù)加強了函數(shù)構(gòu)造器的能力蜘腌,但是沫屡,在實際工作中,筆者覺得函數(shù)構(gòu)造器的用處并不多撮珠。
1.2.4 擴展運算符
剩余參數(shù)是將多個參數(shù)添加進(jìn)數(shù)組沮脖,而擴展運算符則是將數(shù)組的元素分成單個的元素,類似于split的功能芯急。它主要的目的是代替apply勺届。其使用場景如下:
let values = [1,8,3];
// ES5版本
Math.max.apply(Math, values);
// ES6版本
Math.max(...values);
在之前的ES5版本中,要實現(xiàn)求一個數(shù)組的最大數(shù)娶耍,需要使用apply去更改上下文的執(zhí)行環(huán)境免姿,而有了擴展運算符之后,則輕松很多榕酒,并且從語義化角度上來說胚膊,也清晰不少。
1.1.4 函數(shù)的雙重用途
在ES5中奈应,函數(shù)是否調(diào)用new操作符則意味著不同的用途澜掩。沒有new操作符,它就是執(zhí)行函數(shù)體內(nèi)的代碼杖挣。而有了new肩榕,函數(shù)就會執(zhí)行內(nèi)部[[ constructor]]方法,構(gòu)建一個對象惩妇。所以這就是函數(shù)的雙重用途的意思株汉。
在ES5中,判斷函數(shù)是否調(diào)用了new操作歌殃,最簡單也是最流行的一種做法就是使用instanceof這個方法乔妈,但是,這個方法也有明顯的缺陷氓皱,開發(fā)者可以使用apply去改變函數(shù)執(zhí)行的上下文順序路召,從而使instanceof的執(zhí)行判斷出錯勃刨。
function Person(name) {
if (this instanceof Person) {
this.name = name; // 使用 new
} else {
throw new Error("You must use new with Person.")
}
}
var person = new Person("Nicholas");
var notAPerson = Person.call(person, "Michael"); // 奏效了!
因此在ES6中引入了new.target來彌補相關(guān)不足股淡。
function Person(name){
if(typeof new.target != undefined){
this.name =name;
}else{
throw new Error('must with new');
}
}
其底層原理是身隐,在調(diào)用new 操作符時,調(diào)用[[ constructor ]]方法唯灵,new.target才會生成贾铝,(否則為undefined)并且將this對象賦值為原構(gòu)造函數(shù)。
1.1.5 ES6箭頭函數(shù)
之前也學(xué)習(xí)過ES6箭頭函數(shù)埠帕,但是沒有想到的是垢揩,ES6函數(shù)為了增強ES5函數(shù)的一些不足,竟然和傳統(tǒng)的函數(shù)有很多不一樣的特點:
- 沒有this,super,arguments和new.target綁定敛瓷;
- 箭頭函數(shù)不能作為構(gòu)造函數(shù)叁巨,也就是說不能被new,也沒有prototype屬性呐籽;
- 不能更改this的指向(js深惡痛絕的this指向問題)俘种;
- 不能重復(fù)相同的參數(shù)命名。
這些特點是為了減少箭頭函數(shù)內(nèi)部的錯誤與不確定性绝淡,為了js函數(shù)更好的運行宙刘。
2. Vue源碼學(xué)習(xí)
主要是看了第500-900行的代碼,粗略地知道了Vue對數(shù)組的監(jiān)聽牢酵。
首先獲取數(shù)組的原型對象悬包,在這個對象上有數(shù)組的方法。
var arrProto = Array.prototype;
然后使用Object.create的方法創(chuàng)建了一個空對象馍乙,其中它的原型鏈上有數(shù)組方法的集合布近。
var arrMethods = Object.create(arrProto);
創(chuàng)建一個數(shù)組方法的集合:
var methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
];
最關(guān)鍵的一步:對arrMethods進(jìn)行構(gòu)建:
給arrMethods添加屬性
- 遍歷methodsToPatch,在回調(diào)函數(shù)中調(diào)用def函數(shù)給arrMethods添加方法相對應(yīng)的屬性
methodsToPatch.forEach(method => {
def(arrMethods, method, function mutator() {
// 相關(guān)代碼第二步進(jìn)行解析
})
});
function def(obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
});
}?
- muator函數(shù)的定義
function mutator() {
//定義args容器丝格,并且獲取函數(shù)參數(shù)的長度
var args = [],
len = arguments.length;
while (len--) args[len] = arguments[len]; //將類數(shù)組轉(zhuǎn)換成數(shù)組
//這里的this指的就是arrMethods 調(diào)用arrMethods中的方法和參數(shù)
var result = original.apply(this, args);
//監(jiān)聽類 下面代碼就調(diào)用了它的notify和observeArray方法
var ob = this.__ob__;
var inserted;
//如果是push/unshift/splice方法 對inserted進(jìn)行賦值
switch (method) {
case 'push':
case 'unshift':
inserted = args;
break;
case 'splice':
inserted = args.splice(2);
break;
}
if (inserted) {
ob.observeArray(inserted); //對傳入的參數(shù)進(jìn)行監(jiān)聽
}
ob.deep.notify(); //通知視圖發(fā)生變化
return result;
};
3.課程進(jìn)階學(xué)習(xí)
這里總結(jié)性的語言就不寫了撑瞧,拋出問題,測試一下是否能回答出:
有哪3種為DOM元素注冊事件處理函數(shù)的方式显蝌?分別有什么限制和優(yōu)點预伺?
Dom Event接口中哪些屬性和接口需要了解?
如何自定義一個Event事件曼尊?請寫出一個demo;
JS事件的傳播是如何傳播的酬诀?
簡述下面代碼的執(zhí)行順序
// html
<div id='outter'>
<p id='inner'> click </p>
</div>
// js
let outter = document.getElementById('outter');
let inner = document.getElementById('inner');
outter.addEventListener('click', function () {
console.log('outter-true')
}, true);
inner.addEventListener('click', function () {
console.log('inner-true')
}, true);
inner.addEventListener('click', function () {
console.log('inner-false')
}, false);
outter.addEventListener('click', function () {
console.log('outter-false')
}, false);
請解釋一下什么是JS事件代理?
請簡單地寫一下事件代理的demo;
可以使用哪個事件來阻止事件的傳播骆撇?
util.callbackify這個API的作用是什么瞒御?
回調(diào)函數(shù)中的第一個參數(shù)和第二個參數(shù)分別是什么?
請寫出API的具體使用方法:將一個異步函數(shù)轉(zhuǎn)換為錯誤回調(diào)優(yōu)先的函數(shù)
回調(diào)函數(shù)中的
null
有什么意義么神郊?回調(diào)函數(shù)中的錯誤原因可以通過什么屬性獲入热埂趾唱?
generator對象是什么?怎樣才能獲取到蜻懦?
請寫出generator最基本的語法;
調(diào)用一個生成器函數(shù)會立即執(zhí)行函數(shù)體里面的語句么鲸匿?
發(fā)布/訂閱模式和觀察者的區(qū)別是什么?
梳理完本周學(xué)習(xí)的內(nèi)容阻肩,發(fā)現(xiàn)有很多都已經(jīng)忘了,不多說了运授,需要趕緊去復(fù)習(xí)烤惊。