開篇語
忽然有一種感覺,每次學習一個知識點就像是談一場戀愛:從初次邂逅,到彼此瞭解,一切都那麼的符合戀愛的過程!
如果這個知識點再有點”調皮“的話,那簡直是讓人慾仙欲死而又不可自拔!因為你永遠不知道它還有多少面紗等著你揭開,當你自以為對它已經足夠了解的時候,冷不防就是一個盲點迎面砸來。
它簡直就像一個”寶藏女孩“,你要時刻做好迎接”驚喜“的準備!
可能正是因為這種新鮮感,我才能一直保持一種類似亢奮的狀態吧。當然,這只是針對知識而言,對待情感我還是很保守很專一的<( ̄︶ ̄)>
這兩天,我就在和定時器談戀愛,哦不,是在學習定時器( ̄▽ ̄)~*,可沒想到,又給陷進去了……
這不,上一篇文章寫完定時器的返回值後,剛覺得自己對它已經瞭解的清清楚楚明明白白了,夠我炫耀一陣子了,誰成想,喘口氣的功夫,它又給我整出了么蛾子。
惑起
寫完上篇文章後,我就琢磨著裡面的實現程式碼還可以優化一下,於是給改成了下面這個樣子:
<form action="" class="example-form">
<div>
<label for="name">
名稱
</label>
<input class="input-ele" type="text" name="name" id="name" placeholder="please input your name"
autocomplete="off">
</div>
<div style="margin-top:50px;">
<label for="res">
輸入
</label>
<textarea class="input-ele" type="multipart" name="res" id="res" readonly
placeholder="這裡是每一次輸入的結果"></textarea>
</div>
</form>
<script>
window.onload = function () {
const resEle = document.querySelector("#res");
function changeOutputVal() {
resEle.value += `\n${ this.value }`;
}
function throttle(fun, delay) {
let last, deferTimer
return function () {
let now = Date.now();
if (last && now < last + delay) {
clearTimeout(deferTimer);
deferTimer = setTimeout(function () {
last = now;
fun.apply(this);
}, delay)
} else {
last = now;
fun.apply(this);
}
}
}
const inputEle = document.querySelector("#name");
inputEle.addEventListener("input", throttle(changeOutputVal, 1000));
}
</script>
我的修改依據是:
- throttle 方法返回的是一個匿名函式,這個函式正好充當 input 事件的回撥函式
- input 事件回撥函式中的 this 指向的是 inputEle
- 匿名函式中將 this 繫結給了 fun 引數,而實際使用中傳入的是 changeOutputVal 方法
- 所以 changeOutputVal 方法中的 this 指的就是 inputEle,所以在它裡面可以通過
this.value
獲取到 inputEle 的值
看,這邏輯多嚴謹,簡直頭頭是道啊 \( ̄︶ ̄)/
按理說,是沒問題的吧,結果卻出問題了。欲知詳情,請看大螢幕:
這個 undefined 是什麼鬼?!從哪冒出來的?難道我的延時器沒用對?
解惑
面對我的質疑,setTimeout 理直氣壯地說:人家回撥函式中的 this 本來就是指向 window 物件的嘛,你也沒早問啊!
那麼,問題來了:為什麼延時器中的 this 指向的是 window 呢?setTimeout 自己也解釋不清楚了。
得,看來前人誠不我欺也——自己動手,豐衣足食!
凡事不決找 MDN,絕對靠譜!我們來看看 MDN 怎麼說:
由
setTimeout()
呼叫的程式碼執行在與所在函式完全分離的執行環境上。這會導致,這些程式碼中包含的this
關鍵字在非嚴格模式會指向window
(或全域性)物件,嚴格模式下為 undefined,這和所期望的this
的值是不一樣的。
看到這個解釋,我才明白:this 指向 window 物件,原來是因為執行環境的不同導致的。
在上面的程式碼中,因為 window 物件沒有 value 這個屬性,所以 window.value = undefined
。
感覺自己在專業的方向上又邁進了一小步,容我小小地嘚瑟一下!
改錯
既然知道問題出在哪,那就好辦了,我們只需要將 setTimeout 回到函式內部的 this 指向改變一下就好,這裡有以下方案。
使用變數引用外部 this
關鍵程式碼如下:
window.onload = function () {
// some code here
const that = this;
deferTimer = setTimeout(function () {
last = now;
fun.apply(that);
}, delay)
// some code here
}
使用箭頭函式
利用箭頭函式不會改變 this 的指向的特性,改造如下:
window.onload = function () {
// some code here
deferTimer = setTimeout(() => {
last = now;
fun.apply(this);
}, delay)
// some code here
}
結束語
知錯能改,善莫大焉!
寫到這裡,我居然體會到了古人那種”朝聞道,夕死可矣“的滿足感。
在程式設計這條路上,可能遍佈荊棘,但只要我們勤耕不輟,總能開闢出屬於自己的康莊大道!
這雞湯太美味,我先乾為敬,你們隨意!b( ̄▽ ̄)d
~
- ~
- 本文完,感謝閱讀!
~
學習有趣的知識,結識有趣的朋友,塑造有趣的靈魂!
我是〖程式設計三昧〗的作者 隱逸王,我的公眾號是『程式設計三昧』,歡迎關注,希望大家多多指教!
你來,懷揣期望,我有墨香相迎! 你歸,無論得失,唯以餘韻相贈!
知識與技能並重,內力和外功兼修,理論和實踐兩手都要抓、兩手都要硬!