這周因?yàn)榕笥呀Y(jié)婚幫忙的緣故,學(xué)習(xí)的內(nèi)容明顯下降了不少。所以,等明天開始,得需要恢復(fù)之前每天學(xué)習(xí)的強(qiáng)度。
本周的學(xué)習(xí)共分為3塊:
- ES6基礎(chǔ)學(xué)習(xí)與深入;
- Vue源碼閱讀;
- 前端進(jìn)階班的預(yù)習(xí);
下面我們按照上面模塊一起去看一下本周我到底獲得了哪些收貨。
1.ES6學(xué)習(xí)
閱讀完成《深入理解ES6》的第三章。第三章主要講述的是函數(shù)的ES6新特性。
我們都知道ES6是ES5的加強(qiáng)與補(bǔ)充,是為了解決ES5中某些遺留問題而提出的新的解決方案或者加強(qiáng),所以順著這個(gè)思路,我就去做了這樣的筆記。
1.1 ES6函數(shù)新特性
在ES6中,針對(duì)函數(shù),補(bǔ)充了如下的一些特性:
- 參數(shù)默認(rèn)值
- 使用不具名函數(shù)
- 函數(shù)構(gòu)造器增強(qiáng)
- 擴(kuò)展運(yùn)算符
- 函數(shù)的雙重用途
- 塊級(jí)函數(shù)
- 箭頭函數(shù)
- 尾調(diào)用優(yōu)化
1.1.1 參數(shù)默認(rèn)值
傳統(tǒng)的ES5設(shè)置函數(shù)默認(rèn)值需要逐個(gè)對(duì)參數(shù)進(jìn)行設(shè)置,所以代碼量非常多,而且對(duì)于JS這種不限制函數(shù)參數(shù)的行為其擴(kuò)展性也很差。所以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ù)使用第二個(gè)參數(shù)的默認(rèn)值了。
初次之外,還涉及到了2個(gè)比較“冷門的問題”:
- ES6參數(shù)默認(rèn)值是如何影響argument對(duì)象;
- 參數(shù)默認(rèn)值的暫時(shí)性死區(qū);
1.1.2 使用不具名函數(shù)
ES5的不具名的arguments對(duì)象在實(shí)際使用過程中會(huì)有很多的限制。在書中,就通過underscorejs庫中Pick函數(shù)的講解來說出arguments的不足。
// 復(fù)制特定對(duì)象的特定屬性
function pick(object) {
let result = Object.create(null);
// 從第二個(gè)參數(shù)開始處理
for (let i = 1, len = arguments.length; i < len; i++) {
result[arguments[i]] = object[arguments[i]];
}
return result;
}
- 雖然該函數(shù)能處理多個(gè)函數(shù),但是在函數(shù)的表現(xiàn)上則完全看不出;
- 函數(shù)的第一個(gè)參數(shù)是選中的目標(biāo)對(duì)象,從第二個(gè)開始才是需要復(fù)制的屬性。
因此ES6引入了剩余參數(shù)這個(gè)概念,使用剩余函數(shù)對(duì)上述函數(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不同,我們可以單獨(dú)對(duì)剩余函數(shù)進(jìn)行處理。當(dāng)然剩余函數(shù)也有剩余的不足,主要有以下兩點(diǎn):
- 剩余參數(shù)必須要放在最后面;
- 剩余參數(shù)放在setter函數(shù)中不可用,會(huì)報(bào)語法錯(cuò)誤。
1.1.3 函數(shù)構(gòu)造器
作者聲稱,函數(shù)默認(rèn)值加上剩余函數(shù)加強(qiáng)了函數(shù)構(gòu)造器的能力,但是,在實(shí)際工作中,筆者覺得函數(shù)構(gòu)造器的用處并不多。
1.2.4 擴(kuò)展運(yùn)算符
剩余參數(shù)是將多個(gè)參數(shù)添加進(jìn)數(shù)組,而擴(kuò)展運(yùn)算符則是將數(shù)組的元素分成單個(gè)的元素,類似于split的功能。它主要的目的是代替apply。其使用場(chǎng)景如下:
let values = [1,8,3];
// ES5版本
Math.max.apply(Math, values);
// ES6版本
Math.max(...values);
在之前的ES5版本中,要實(shí)現(xiàn)求一個(gè)數(shù)組的最大數(shù),需要使用apply去更改上下文的執(zhí)行環(huán)境,而有了擴(kuò)展運(yùn)算符之后,則輕松很多,并且從語義化角度上來說,也清晰不少。
1.1.4 函數(shù)的雙重用途
在ES5中,函數(shù)是否調(diào)用new操作符則意味著不同的用途。沒有new操作符,它就是執(zhí)行函數(shù)體內(nèi)的代碼。而有了new,函數(shù)就會(huì)執(zhí)行內(nèi)部[[ constructor]]方法,構(gòu)建一個(gè)對(duì)象。所以這就是函數(shù)的雙重用途的意思。
在ES5中,判斷函數(shù)是否調(diào)用了new操作,最簡(jiǎn)單也是最流行的一種做法就是使用instanceof這個(gè)方法,但是,這個(gè)方法也有明顯的缺陷,開發(fā)者可以使用apply去改變函數(shù)執(zhí)行的上下文順序,從而使instanceof的執(zhí)行判斷出錯(cuò)。
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來彌補(bǔ)相關(guān)不足。
function Person(name){
if(typeof new.target != undefined){
this.name =name;
}else{
throw new Error('must with new');
}
}
其底層原理是,在調(diào)用new 操作符時(shí),調(diào)用[[ constructor ]]方法,new.target才會(huì)生成,(否則為undefined)并且將this對(duì)象賦值為原構(gòu)造函數(shù)。
1.1.5 ES6箭頭函數(shù)
之前也學(xué)習(xí)過ES6箭頭函數(shù),但是沒有想到的是,ES6函數(shù)為了增強(qiáng)ES5函數(shù)的一些不足,竟然和傳統(tǒng)的函數(shù)有很多不一樣的特點(diǎn):
- 沒有this,super,arguments和new.target綁定;
- 箭頭函數(shù)不能作為構(gòu)造函數(shù),也就是說不能被new,也沒有prototype屬性;
- 不能更改this的指向(js深惡痛絕的this指向問題);
- 不能重復(fù)相同的參數(shù)命名。
這些特點(diǎn)是為了減少箭頭函數(shù)內(nèi)部的錯(cuò)誤與不確定性,為了js函數(shù)更好的運(yùn)行。
2. Vue源碼學(xué)習(xí)
主要是看了第500-900行的代碼,粗略地知道了Vue對(duì)數(shù)組的監(jiān)聽。
首先獲取數(shù)組的原型對(duì)象,在這個(gè)對(duì)象上有數(shù)組的方法。
var arrProto = Array.prototype;
然后使用Object.create的方法創(chuàng)建了一個(gè)空對(duì)象,其中它的原型鏈上有數(shù)組方法的集合。
var arrMethods = Object.create(arrProto);
創(chuàng)建一個(gè)數(shù)組方法的集合:
var methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
];
最關(guān)鍵的一步:對(duì)arrMethods進(jìn)行構(gòu)建:
給arrMethods添加屬性
- 遍歷methodsToPatch,在回調(diào)函數(shù)中調(diào)用def函數(shù)給arrMethods添加方法相對(duì)應(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方法 對(duì)inserted進(jìn)行賦值
switch (method) {
case 'push':
case 'unshift':
inserted = args;
break;
case 'splice':
inserted = args.splice(2);
break;
}
if (inserted) {
ob.observeArray(inserted); //對(duì)傳入的參數(shù)進(jìn)行監(jiān)聽
}
ob.deep.notify(); //通知視圖發(fā)生變化
return result;
};
3.課程進(jìn)階學(xué)習(xí)
這里總結(jié)性的語言就不寫了,拋出問題,測(cè)試一下是否能回答出:
有哪3種為DOM元素注冊(cè)事件處理函數(shù)的方式?分別有什么限制和優(yōu)點(diǎn)?
Dom Event接口中哪些屬性和接口需要了解?
如何自定義一個(gè)Event事件?請(qǐng)寫出一個(gè)demo;
JS事件的傳播是如何傳播的?
簡(jiǎn)述下面代碼的執(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);
請(qǐng)解釋一下什么是JS事件代理?
請(qǐng)簡(jiǎn)單地寫一下事件代理的demo;
可以使用哪個(gè)事件來阻止事件的傳播?
util.callbackify這個(gè)API的作用是什么?
回調(diào)函數(shù)中的第一個(gè)參數(shù)和第二個(gè)參數(shù)分別是什么?
請(qǐng)寫出API的具體使用方法:將一個(gè)異步函數(shù)轉(zhuǎn)換為錯(cuò)誤回調(diào)優(yōu)先的函數(shù)
回調(diào)函數(shù)中的
null有什么意義么?回調(diào)函數(shù)中的錯(cuò)誤原因可以通過什么屬性獲?。?/p>
generator對(duì)象是什么?怎樣才能獲取到?
請(qǐng)寫出generator最基本的語法;
調(diào)用一個(gè)生成器函數(shù)會(huì)立即執(zhí)行函數(shù)體里面的語句么?
發(fā)布/訂閱模式和觀察者的區(qū)別是什么?
梳理完本周學(xué)習(xí)的內(nèi)容,發(fā)現(xiàn)有很多都已經(jīng)忘了,不多說了,需要趕緊去復(fù)習(xí)。