您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“怎么實(shí)現(xiàn)call、apply、bind”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
首先我們來(lái)給call下個(gè)定義:
call方法在使用一個(gè)指定的 this 值和若干個(gè)指定的參數(shù)值的前提下調(diào)用某個(gè)函數(shù)或方法。
舉個(gè)例子:
var foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar.call(foo); // 1
從上面代碼的執(zhí)行結(jié)果,我們可以看到,call首先改變了this的指向,使函數(shù)的this指向了foo,然后使bar函數(shù)執(zhí)行了。
總結(jié)如下:1、call改變函數(shù)this指向,2、調(diào)用函數(shù)
思考一下:我們?nèi)绾螌?shí)現(xiàn)上面的效果呢?代碼改造如下:
//將bar函數(shù)掛載到foo對(duì)象上,使其成為foo的方法,用foo.bar來(lái)調(diào)用var foo = { value:1, bar:function(){ console.log(this.value) }}foo.bar() //1
仔細(xì)觀察一下我們做了什么,將bar函數(shù)掛載到foo對(duì)象上,使其成為foo的方法,用foo.bar來(lái)調(diào)用。
再來(lái)看上面代碼的執(zhí)行結(jié)果:打印1,有沒(méi)有什么啟發(fā)呢?為了模擬call方法,我們可不可以這樣做呢:
a、將函數(shù)設(shè)為某個(gè)對(duì)象的屬性(或者方法)
b、通過(guò)該對(duì)象的屬性調(diào)用該函數(shù)
c、將該對(duì)象上的這個(gè)屬性(或者方法)
代碼如下:
Function.prototype.myCall = function(context) { context = context || window //將函數(shù)掛載到對(duì)象的fn屬性上 context.fn = this //處理傳入的參數(shù) const args = [...arguments].slice(1) //通過(guò)對(duì)象的屬性調(diào)用該方法 const result = context.fn(...args) //刪除該屬性 delete context.fn return result}
我們看一下上面的代碼:
1、首先我們對(duì)參數(shù)context做了兼容處理,不傳值,context默認(rèn)值為window。
2、然后我們將函數(shù)掛載到context上面,context.fn = this;
3、處理參數(shù),將傳入myCall的參數(shù)截取,去除第一位,然后轉(zhuǎn)為數(shù)組;
4、調(diào)用context.fn,此時(shí)fn的this指向context;
5、刪除對(duì)象上的屬性 delete context.fn
5、將結(jié)果返回。
以此類推,我們順便實(shí)現(xiàn)一下apply,唯一不同的是參數(shù)的處理,代碼如下:
Function.prototype.myApply = function(context) {
context = context || window
context.fn = this
let result
// myApply的參數(shù)形式為(obj,[arg1,arg2,arg3]);
// 所以myApply的第二個(gè)參數(shù)為[arg1,arg2,arg3]
// 這里我們用擴(kuò)展運(yùn)算符來(lái)處理一下參數(shù)的傳入方式
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn
return result
}
以上便是call和apply的模擬實(shí)現(xiàn),唯一不同的是對(duì)參數(shù)的處理方式。
接著再來(lái)思考一下bind的實(shí)現(xiàn),在模擬bind的實(shí)現(xiàn)之前,先看一下bind的使用案例:
var obj = {a:1};function bar(){ console.log(this.a);}bar.bind(obj)();
我們看到,bind函數(shù)雖然也能改變bar函數(shù)的this,但是改變后,函數(shù)并不會(huì)執(zhí)行,只是返回一個(gè)新的函數(shù),想執(zhí)行就得繼續(xù)調(diào)用,仔細(xì)觀察第五行代碼的寫法。
根據(jù)上面的使用案例,我們先實(shí)現(xiàn)一個(gè)簡(jiǎn)單版本的bind:
Function.prototype.myBind = function(ctx) { return () => { // 要用箭頭函數(shù),否則 this 指向錯(cuò)誤 return this.call(ctx) }}var obj = {a:1};function bar(){ console.log(this.a);}bar.myBind(obj)();
但是這樣比較簡(jiǎn)陋,函數(shù)的參數(shù)一多就不能處理了,如下面這種情況:
bar.bind(obj, 2)(2)// orbar.bind(obj)(2, 2)
為了兼容bind調(diào)用時(shí)滿足參數(shù)傳遞的不同方式,代碼修改如下:
Function.prototype.myBind = function(ctx, ...argv1) { return (...argv2) => { return this.call(ctx, ...argv1, ...argv2) }}//測(cè)試代碼var obj = {a:1};function bar(b,c){ console.log(this.a+b+c);}bar.myBind(obj)(20,30);bar.myBind(obj,20,30)();
“怎么實(shí)現(xiàn)call、apply、bind”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。