一文搞懂JavaScript中bind,apply,call的實現(xiàn)_第1頁
一文搞懂JavaScript中bind,apply,call的實現(xiàn)_第2頁
一文搞懂JavaScript中bind,apply,call的實現(xiàn)_第3頁
一文搞懂JavaScript中bind,apply,call的實現(xiàn)_第4頁
一文搞懂JavaScript中bind,apply,call的實現(xiàn)_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第一文搞懂JavaScript中bind,apply,call的實現(xiàn)目錄bind、call和apply的用法bindcallapply實現(xiàn)bind實現(xiàn)call和apply總結(jié)bind、call和apply都是Function原型鏈上面的方法,因此不管是使用function聲明的函數(shù),還是箭頭函數(shù)都可以直接調(diào)用。這三個函數(shù)在使用時都可以改變this指向,本文就帶你看看如何實現(xiàn)bind、call和apply。

bind、call和apply的用法

bind

bind()方法可以被函數(shù)對象調(diào)用,并返回一個新創(chuàng)建的函數(shù)。

語法:

function.bind(thisArg[,arg1[,arg2[,...]]])

bind()會將第一個參數(shù)作為新函數(shù)的this,如果未傳入?yún)?shù)列表,或者第一個參數(shù)是null或undefined,那么新函數(shù)的this將會是該函數(shù)執(zhí)行作用域的this。使用bind()應(yīng)注意以下事項:

返回一個新的函數(shù),但是不會立即執(zhí)行該函數(shù)根據(jù)傳入的參數(shù)列表綁定this指向,如果未傳入thisArg,那么需要明確this的指向如果是箭頭函數(shù),無法改變this,只能改變參數(shù),這一點我們在這些情況下不建議你使用箭頭函數(shù)也講到過

舉個例子:

正常使用

functionfn(a){

console.log(this,a)

constfn1=fn.bind({x:100});//fn1是一個函數(shù),但是并沒有立即執(zhí)行

fn1();//{x:100}100

console.log(fn===fn1);//false,bind返回的是一個新的函數(shù)

箭頭函數(shù)

constfn=(a)={

console.log(this,a);

constfn1=fn.bind({x:100},100);//返回一個新的函數(shù)fn1,不會執(zhí)行

fn1();//window,100箭頭函數(shù)通過bind返回的函數(shù)無法修改其this指向

未綁定this,或綁定到null、undefined

constfn=(a)={

console.log(this,a);

constfn1=fn.bind();//未綁定

constfn2=fn.bind(null);//綁定null

constfn3=fn.bind(undefined);//綁定undefined

fn1();//綁定到執(zhí)行作用域,默認(rèn)為window

fn2();//綁定到執(zhí)行作用域,默認(rèn)為window

fn3();//綁定到執(zhí)行作用域,默認(rèn)為window

callapply

與bind不同,call和apply都是用來執(zhí)行函數(shù)的,可以解決執(zhí)行的函數(shù)的this指向問題。

語法:

function.call(thisArg,arg1,arg2,...)

function.apply(thisArg,argsArray)

call的參數(shù)列表是可選的,如果傳入的thisArg是null或者undefined,那么會自動替換為全局對象;如果是傳入的原始值,則會替換為原始值對應(yīng)的包裝類型。apply的用法和call類似,不同點在于其額外傳入的參數(shù)是一個數(shù)組或類數(shù)組對象,而call的額外參數(shù)是不確定參數(shù)。

舉個栗子:

functionfn(a,b){

console.log(this,a,b);

fn.call({x:100},10,20);//{x:100}1020

fn.apply({x:100},[10,20]);//{x:100}1020

call和apply無法修改箭頭函數(shù)的this指向:

constfn=(a,b)={

console.log(this,a,b);

fn.call({x:100},10,20);//Window1020

fn.apply({x:100},[10,20]);//Window1020

簡單回顧了以下bind、call、apply的使用,接下來就看看應(yīng)該如何來實現(xiàn)。

實現(xiàn)bind

根據(jù)我們剛剛使用的bind(),在設(shè)計時需要如下考慮:

最終返回的是一個新的函數(shù),可通過function來聲明需要綁定新函數(shù)的this需要綁定運行時的參數(shù),可通過apply或call來實現(xiàn)

實現(xiàn)代碼:

//通過原型鏈注冊方法

//context:傳遞的上下文this;bindArgs表示需要綁定的額外參數(shù)

Ftotype.newBind=function(context,...bindArgs){

constself=this;//當(dāng)前調(diào)用bind的函數(shù)對象

//返回的函數(shù)本身也是可以再傳入?yún)?shù)的

returnfunction(...args){

//拼接參數(shù)

constnewArgs=bindArgs.concat(args);

returnself.apply(context,newArgs)

functionfn(a,b){

console.log(this,a,b);

constfn1=fn.newBind({x:100},10);

fn1(20);//{x:100}1020

bind()返回的是一個新函數(shù),執(zhí)行新函數(shù)就相當(dāng)于是通過call或apply來調(diào)用原函數(shù),并傳入this和參數(shù)。

實現(xiàn)call和apply

在實現(xiàn)bind的過程中,我們使用了apply來完成this的綁定,那么要實現(xiàn)apply又應(yīng)該用什么來綁定this呢?可能會有小機(jī)靈鬼發(fā)現(xiàn),好像在apply中使用call,在call中使用apply也可以完成this綁定。這不就形成了嵌套嘛,不是我們最終想要的。

我們先來

call和apply的應(yīng)用:

bind返回一個新的函數(shù),并不會執(zhí)行;call和apply會立即執(zhí)行函數(shù)綁定this傳入執(zhí)行參數(shù)

舉個栗子:

functionfn(a,b){

console.log(this,a,b);

fn.call({x:100},10,20);//{x:100}1020

fn.apply({x:100},[10,20]);//{x:100}1020

call和apply的實現(xiàn)效果是一樣的,都是立即執(zhí)行函數(shù),不同的是call需要傳入單個或者多個參數(shù),apply可以傳入一個參數(shù)數(shù)組。

如何在函數(shù)執(zhí)行時綁定this:

constobj={x:100,fn(){this.x}}執(zhí)行obj.fn(),此時fn()內(nèi)部的this指向的就是obj可以借此實現(xiàn)函數(shù)綁定this

使用過Vue的朋友都知道,Vue實例其實就是一個對象,其里面的方法在調(diào)用時,this就會指向當(dāng)前對象。舉個栗子:

letobj={

key:'key',

getKey:()={

returnthis.key;

getKey2(){

returnthis.key;

obj.getKey();//this指向window,返回值取決于window中是否有對應(yīng)的屬性

obj.getKey2();//this指向obj,返回'key'

這個例子在這些情況下不建議你使用箭頭函數(shù)也是有提及的,感興趣的朋友可以去看看。根據(jù)此原理,我們就可以來嘗試給函數(shù)綁定this了:某函數(shù)調(diào)用apply,那么我們就將這個函數(shù)添加到傳入的this對象中(如果未傳入則this為全局對象,如果傳入的是原始值,則使用其包裝類型),然后使用()來執(zhí)行函數(shù),這個時候函數(shù)的this指向的就是我們傳入的this了。

實現(xiàn)代碼:

Ftotype.newCall=function(context,...args){

if(context==null)context=globalThis;//如果傳入的上下文是null或者undefined,則使用全局globalThis,一般指向的就是window

if(typeofcontext!=='object')context=newObject(context);//如果是原始類型(數(shù)字、字符串、布爾值等),則使用其包裝類型

constfnKey=Symbol();//使用Symbol可確保key值不會重復(fù),避免屬性覆蓋

context[fnKey]=this;//this指向的是當(dāng)前調(diào)用newCall的函數(shù)

console.log(context[fnKey]);//打印當(dāng)前函數(shù)以及上下文this

console.log(context);

constres=context[fnKey](...args);//執(zhí)行函數(shù),函數(shù)的this指向為context

deletecontext[fnKey];//刪除fn,防止污染

returnres;//返回結(jié)果

fn.newCall({x:100},10,20);//{x:100}1020

functionfn(a,b){

console.log(this,a,b);

這樣我們就實現(xiàn)了call,那么apply實現(xiàn)類似,只不過傳入的額外參數(shù)要變成數(shù)組或類數(shù)組的方式

Ftotype.newCall=function(context,args){

if(context==null)context=globalThis;//如果傳入的上下文是null或者undefined,則使用全局globalThis,一般指向的就是window

if(typeofcontext!=='object')context=newObject(context);//如果是原始類型(數(shù)字、字符串、布爾值等),則使用其包裝類型

constfnKey=Symbol();//使用Symbol可確保key值不會重復(fù),避免屬性覆蓋

context[fnKey]=this;//this指向的是當(dāng)前調(diào)用newCall的函數(shù)

console.log(context[fnKey]);//打印當(dāng)前函數(shù)以及上下文this

console.log(context);

constres=context[fnKey](...args);//執(zhí)行函數(shù),函數(shù)的this指向為context

deletecontext[fnKey];//刪除fn,防止污染

returnres;//返回結(jié)果

fn.newCall({x:100},10,20);//{x:100}1020

functionfn(a,b){

console.log(this,a,b);

注意打印的當(dāng)前函數(shù)以及上下文:

實現(xiàn)call和apply與bind有很大的不同就是如何來處理this

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論