大家好!!!註冊一年多的第一篇博客。 自我介紹: 本人非電腦專業出身,轉行進入前端半年時間,寫的東西可能觀賞性不強,一起進步吧道友們。。。 接下來的一段時間, 我都會不定期整理自己理解的js知識點, 歡迎各路道友吐槽。 進入正題...... (針對新手,老司機不要嘲笑我) 首先, bind/cal ...
大家好!!!註冊一年多的第一篇博客。
自我介紹: 本人非電腦專業出身,轉行進入前端半年時間,寫的東西可能觀賞性不強,一起進步吧道友們。。。
接下來的一段時間, 我都會不定期整理自己理解的js知識點, 歡迎各路道友吐槽。
進入正題...... (針對新手,老司機不要嘲笑我)
首先, bind/call/apply 這改變this指向的三兄弟我們都很熟悉了, 還有其他改變this指向的方法這裡就不多說了哈,要不就跑題了。。。。
你需要知道的前提 : 這三貨都是函數原型(Function.prototype)上的方法, 所以只有函數可以調用。
小白 : “原型是啥?” 每一個構造函數(其實就是普通函數,函數名首字母大寫而已)都有一個prototype原型對象,當你引用某個實例對象上的屬性時, 會先查找該對象本身有沒有該屬性,有就用,沒有就會去構造這個實例的構造函數的原型上去找,還沒有的話就會沿著構造函數的原型對象的__proto__屬性往上找......haha, 好像又跑題了, 關於原型鏈和繼承可以自行百度
真的進入正題。。。。。。
它們不是函數上的方法嗎, 我們先定義個函數, 後面來改變這個函數的this指向
function out(age, sex, type) {
console.log(age, sex, this.age, this.sex, type);
}
分別輸出傳入的參數age, sex, type 和 this 上的age , sex,
然後定義個對象, 後面讓this指向該對象, 沒錯,此對象描述的就是我
let my = {
age : 16,
sex : 'handsome man'
};
先試試bind, 先會用然後再來實現, 由於bind可以傳兩次參數,你可以這樣傳
const bindFunction = out.bind(my,50); //this 指向my 不會直接執行 返回一個明確this指向的函數 bindFunction('women','bind'); // 傳參執行
還可以這樣傳,想怎麼傳就怎麼傳,只要確保.bind後的第一個參數是你要改變this指向的對象, (如果什麼都不傳,this指向window)
const bindFunction = out.bind(my); //this 指向my 不會直接執行 返回一個明確this指向的函數 bindFunction('50','women','bind'); // 傳參執行
執行後輸出 :
50 "women" 16 "handsome man" "bind"
總結一下我們要模擬的bind
1. 函數A調用bind返回一個可執行的函數B, 調用bind時可傳參 可不穿參, 不穿參時this指向window
2. 調用B可繼續傳參, 兩次傳參合並
3. new B() 的構造函數依然是A, 而不是B,並且因為new操作符改變this指向的優先順序最高,所以如果使用了new操作符,this指向不應該變,就是該是啥是啥(劃重點)
上代碼 :
Function.prototype.myBind = function (target) { // bind 是 function 上的 方法 this 指向 target
if (typeof this !== 'function') {
throw new TypeError('not a function')
};
const _this = this, // 保存一下this
args = Array.prototype.slice.call(arguments, 1),// arguments是類數組,沒有 slice 方法 保存第一次傳入的參數
temp = function () {}; // 定義一個中間函數
const f = function () {
return _this.apply(this instanceof temp ? this : (target || window), args.concat([].slice.call(arguments))); // 合併兩次傳的參數
};
temp.prototype = _this.prototype; // 讓temp 的原型 等於 this的原型
f.prototype = new temp(); //f 繼承 temp 聖杯繼承可以瞭解下
return f;
};
先正常執行一下myBind:
const bind1 = this.out.myBind(my, 50);
// const bind2 = new bind1('women','myBind');
const bind3 = bind1('women','myBind');
結果是:
50 "women" 16 "handsome man" "myBind"
OK , 和bind的輸出結果一樣
再使用new操作符:
const bind1 = this.out.myBind(my, 50);
const bind2 = new bind1('women','myBind');
// const bind3 = bind1('women','myBind');
結果是這樣:此時this不再指向my, 而是指向new 出來的一個空對象,所以this上沒有age和sex兩個屬性
50 "women" undefined undefined "myBind"
到此bind 我們已經完美模擬出來了 -------- 是不是有點小激動 ----------細心的道友會發現myBind 里 還借用了call 和apply!!! 這還不行啊