二十二世纪古墓奇兵爱慕影院

小梁建站專注重慶中小企業網站建設SEO優化,讓您網站更具價值!

當前位置:首頁 > WEB前端學習 > 教你如何理解this及call,apply和bind的用法

教你如何理解this及call,apply和bind的用法

時間:2018-08-18 23:24 來源:重慶網站制作公司(www.l2qz.net) 作者:重慶網站建設公司

教你如何理解this及call,apply和bind的用法
 


教你如何理解this及call,apply和bind的用法
 
JavaScript中最容易被誤解的一個方面是this關鍵字。在這篇文章中,將通過學習四個規則來確定此關鍵字引用的內容。隱式綁定,顯式綁定,new綁定和window綁定。在介紹這些時,你還將學習一些其他令人困惑的JavaScript部分,例如.call,.apply,.bind和new關鍵字。
 
1   前言
 
   
在深入研究JavaScript中這個關鍵字的細節之前,我們先退一步想一想,為什么這個關鍵字存在于第一位。這個關鍵字允許你重用具有不同上下文的函數。換句話說,"this"關鍵字允許你在調用函數或方法時決定哪個對象應該是焦點。在此之后我們談論的一切都將建立在這個想法之上。我們希望能夠在不同的上下文中或在不同的對象中重用函數或方法。
 
我們要看的第一件事是如何判斷此關鍵字引用的內容。 當你試圖回答這個問題時,你需要問自己的第一個也是最重要的問題是“這個函數在哪里被調用?"。你可以通過查看調用this關鍵字的函數的位置來判斷此關鍵字引用的內容的唯一方法。
 
為了用一個你已經熟悉的例子來證明這一點,比如我們有一個greet函數,它接受了一個alert消息。
 
function
 greet 
(
name
)
 
{
 
  alert
(`
Hello
,
 my name is $
{
name
}`)
 
}
 
如果我要問你確切的警告,你的回答是什么? 只給出函數定義,就不可能知道。 為了知道名字是什么,你必須看看greet的函數調用。
 
greet
(
'Tyler'
)
 
原理是完全相同的,找出這個關鍵字的引用,你甚至,就像你對函數的正常參數一樣 - 它會根據函數的調用方式而改變。
 
現在我們知道為了弄清楚this關鍵字引用的內容,你必須查看函數定義,讓我們在實際查看函數定義時建立四個規則來查找。 他們是:
 
隱式綁定
 
 
 
new綁定
 
window綁定
 
 
 
2   隱式綁定
 
 
 
   
請記住,這里的目標是能夠使用this關鍵字查看函數定義并告訴它引用的內容。 執行此操作的第一個也是最常見的規則稱為隱式綁定。 我想說絕大多數情況它會告訴你這個關鍵字引用了什么。
 
假設我們有一個看起來像這樣的對象
 
const
 user 
=
 
{
 
  name
:
 
'Tyler'
,
 
  age
:
 
27
,
 
  greet
()
 
{
 
    alert
(`
Hello
,
 my name is $
{
this
.
name
}`)
 
  
}
 
}
 
現在,如果你要在user對象上調用greet方法,那么你可以使用點表示法。
 
user
.
greet
()
 
這將我們帶到隱式綁定規則的主要關鍵點。 為了弄清楚this關鍵字引用的內容,首先,在調用函數時,請查看點的左側。 如果存在“點”,請查看該點的左側以查找此關鍵字引用的對象。
 
在上面的示例中,user對象是“點的左側”,這意味著此關鍵字引用user對象。 因此,就像在greet方法中,JavaScript解釋器將此更改為user。
 
greet
()
 
{
 
  
// alert(`Hello, my name is ${this.name}`)
 
  alert
(`
Hello
,
 my name is $
{
user
.
name
}`)
 
// Tyler
 
}
 
讓我們來看一個類似但稍微更高級的例子。 現在,我們不僅要擁有名稱,年齡和問候屬性,還要為我們的user對象提供一個mother屬性,該屬性也有名稱和greet屬性。
 
const
 user 
=
 
{
 
  name
:
 
'Tyler'
,
 
  age
:
 
27
,
 
  greet
()
 
{
 
    alert
(`
Hello
,
 my name is $
{
this
.
name
}`)
 
  
},
 
  mother
:
 
{
 
    name
:
 
'Stacey'
,
 
    greet
()
 
{
 
      alert
(`
Hello
,
 my name is $
{
this
.
name
}`)
 
    
}
 
  
}
 
}
 
現在問題變成了,下面的每個調用會發出什么alert?
 
user
.
greet
()
 
user
.
mother
.
greet
()
 
每當我們試圖弄清楚這個關鍵字引用的內容時,我們需要查看調用并看看“左邊的點”是什么。 在第一次調用中,user位于點的左側,這意味著這將引用user。 在第二次調用中,mother位于點的左側,這意味著這將引用mother。
 
user
.
greet
()
 
// Tyler
 
user
.
mother
.
greet
()
 
// Stacey
 
如前所述,絕大多數會有一個“左邊的點”的對象。 這就是為什么在弄清楚這個關鍵字引用的內容時應該采取的第一步是“向左看點”。 但是,如果沒有點怎么辦? 這將我們帶入下一個規則。
 
 
 
3   顯式綁定
 
 
 
   
現在,如果我們的greet函數不是user對象的方法,那么它就是它自己的獨立函數。
 
function
 greet 
()
 
{
 
  alert
(`
Hello
,
 my name is $
{
this
.
name
}`)
 
}
 
 
const
 user 
=
 
{
 
  name
:
 
'Tyler'
,
 
  age
:
 
27
,
 
}
 
我們知道,為了告訴this關鍵字引用的內容,我們首先要查看函數的調用位置。 現在這提出了一個問題,我們如何調用greet但是使用this關鍵字引用user對象來調用它。 我們不能像之前那樣做user.greet()因為user沒有greet方法。 在JavaScript中,每個函數都包含一個允許你完成此操作的方法,那就是call方法。
 
“call”是每個函數的一個方法,它允許你調用函數,指定調用函數的上下文。
 
考慮到這一點,我們可以使用以下代碼在user的上下文中調用greet。
 
greet
.
call
(
user
)
 
同樣,call是每個函數的屬性,傳遞給它的第一個參數將是調用函數的上下文。 換句話說,傳遞給調用的第一個參數將是該函數中的this關鍵字引用的內容。
 
這是規則2(顯式綁定)的基礎,因為我們明確地(使用.call)指定this關鍵字引用的內容。
 
現在讓我們稍微修改一下greet函數。 如果我們還想傳遞一些參數怎么辦? 比如:
 
function
 greet 
(
lang1
,
 lang2
,
 lang3
)
 
{
 
  alert
(`
Hello
,
 my name is $
{
this
.
name
}
 and I know $
{
lang1
},
 $
{
lang2
},
 and $
{
lang3
}`)
 
}
 
現在,為了將參數傳遞給使用.call調用的函數,在指定第一個作為上下文的參數后,將它們逐個傳遞給它們。
 
function
 greet 
(
lang1
,
 lang2
,
 lang3
)
 
{
 
  alert
(`
Hello
,
 my name is $
{
this
.
name
}
 and I know $
{
lang1
},
 $
{
lang2
},
 and $
{
lang3
}`)
 
}
 
 
const
 user 
=
 
{
 
  name
:
 
'Tyler'
,
 
  age
:
 
27
,
 
}
 
 
const
 languages 
=
 
[
'JavaScript'
,
 
'Ruby'
,
 
'Python'
]
 
 
greet
.
call
(
user
,
 languages
[
0
],
 languages
[
1
],
 languages
[
2
])
 
它顯示了如何將參數傳遞給使用.call調用的函數。 但是,正如你可能已經注意到的那樣,必須從我們的語言數組中逐個傳遞參數,這有點令人討厭。 如果我們可以將整個數組作為第二個參數傳入并且JavaScript會將它們傳播給我們,那將是很好的。 對我們來說這是個好消息,這正是.apply所做的。 .appall與.call完全相同,但不是逐個傳入參數,而是傳入一個數組,它會將這些數據作為函數中的參數傳遞出去。
 
所以現在使用.apply,我們的代碼可以改為這個(下面),其他一切都保持不變。
 
const
 languages 
=
 
[
'JavaScript'
,
 
'Ruby'
,
 
'Python'
]
 
 
// greet.call(user, languages[0], languages[1], languages[2])
 
greet
.
apply
(
user
,
 languages
)
 
到目前為止,在我們的“顯式綁定”規則下,我們已經了解了.call和.apply,它們都允許你調用一個函數,指定this關鍵字將在該函數內部引用的內容。 這條規則的最后一部分是.bind。 .bind與.call完全相同,但它不會立即調用該函數,而是返回一個可以在以后調用的新函數。 因此,如果我們使用.bind改變我們之前的代碼,它看起來就像這樣
 
function
 greet 
(
lang1
,
 lang2
,
 lang3
)
 
{
 
  alert
(`
Hello
,
 my name is $
{
this
.
name
}
 and I know $
{
lang1
},
 $
{
lang2
},
 and $
{
lang3
}`)
 
}
 
 
const
 user 
=
 
{
 
  name
:
 
'Tyler'
,
 
  age
:
 
27
,
 
}
 
 
const
 languages 
=
 
[
'JavaScript'
,
 
'Ruby'
,
 
'Python'
]
 
 
const
 newFn 
=
 greet
.
bind
(
user
,
 languages
[
0
],
 languages
[
1
],
 languages
[
2
])
 
newFn
()
 
// alerts "Hello, my name is Tyler and I know JavaScript, Ruby, and Python"
 
 
 
4   new綁定
 
 
 
   
確定this關鍵字引用內容的第三條規則稱為new綁定。 如果你不熟悉JavaScript中的新關鍵字,那么每當你使用new關鍵字調用函數時,JavaScript解釋器都會創建一個全新的對象并將其稱為this對象。 因此,如果使用new調用函數,則this關鍵字引用解釋器創建的新對象。
 
function
 
User
 
(
name
,
 age
)
 
{
 
  
/*
 
    Under the hood, JavaScript creates a new object called `this`
 
    which delegates to the User's prototype on failed lookups. If a
 
    function is called with the new keyword, then it's this new object
 
    that interpretor created that the this keyword is referencing.
 
  */
 
 
  
this
.
name 
=
 name
 
  
this
.
age 
=
 age
 
}
 
 
const
 me 
=
 
new
 
User
(
'Tyler'
,
 
27
)
 
 
 
5  window綁定
 
 
 
   
假設我們有以下代碼
 
function
 sayAge 
()
 
{
 
  console
.
log
(`
My
 age is $
{
this
.
age
}`)
 
}
 
 
const
 user 
=
 
{
 
  name
:
 
'Tyler'
,
 
  age
:
 
27
 
}
 
如前所述,如果你想在user的上下文中調用sayAge,可以使用.call,.apply或.bind。 如果我們不使用任何這些,而只是像往常一樣調用sayAge會發生什么
 
sayAge
()
 
// My age is undefined
 
你得到的是,毫無疑問的是undefined的,因為this.age將是未定義的。 這里的事情變得瘋狂了。這里真正發生的是因為點的左邊沒有任何內容,我們沒有使用.call,.apply,.bind或new關鍵字,JavaScript默認這是引用window對象。 這意味著如果我們將一個age屬性添加到window對象,那么當我們再次調用我們的sayAge函數時,this.age將不再是未定義的,而是它將是window對象上的age屬性。 不相信我? 運行此代碼,
 
window
.
age 
=
 
27
 
function
 sayAge 
()
 
{
 
  console
.
log
(`
My
 age is $
{
this
.
age
}`)
 
}
 
非常粗糙,對嗎? 這就是為什么第四個規則是window綁定。 如果沒有滿足其他規則,則JavaScript將默認this關鍵字引用window對象。
 
在ES5中添加的嚴格模式中,JavaScript將做正確的事情,而不是默認為window對象只是將“this”保持為未定義。
 
'use strict'
 
 
window
.
age 
=
 
27
 
 
function
 sayAge 
()
 
{
 
  console
.
log
(`
My
 age is $
{
this
.
age
}`)
 
}
 
 
sayAge
()
 
// TypeError: Cannot read property 'age' of undefined
 
 
6   總結
 
   
因此,將所有規則付諸實踐,每當我在函數內部看到this關鍵字時,我們可以采用以下步驟弄清楚它所引用的內容。
 
1. 查看調用函數的位置
 
2. 點左邊有一個對象嗎? 如果是這樣,那就是“this”關鍵字引用的內容。 如果沒有,繼續#3
 
3. 該函數是使用“call”,“apply”還是“bind”調用的? 如果是這樣,它將明確說明“this”關鍵字引用的內容。 如果沒有,繼續#4
 
4. 是否使用“new”關鍵字調用了該函數? 如果是這樣,“this”關鍵字引用由JavaScript解釋器創建的新創建的對象。 如果沒有,繼續#5
 
5. 你是在“嚴格模式”嗎? 如果是,則“this”關鍵字未定義。如果沒有,繼續#6
 
6. 是的,JavaScript很奇怪。 “this”引用了“window”對象。
 
 

版權聲明:本文:教你如何理解this及call,apply和bind的用法 由重慶網站制作公司(www.l2qz.net)原創內容,如需要轉載請注明原文網址:重慶網站建設公司http://www.l2qz.net/

 
喜歡看,就分享到:

圍觀: 9999次 | 責任編輯:重慶網站建設公司

回到頂部
二十二世纪古墓奇兵爱慕影院 加拿大pc28软件 儿童早教软件 黑龙江11选5app 红宝石彩票中奖图片 pk10技巧冠亚计划 玩龙虎合怎么稳赚 比分网即时比分500 北京pk赛车app下载 dlt大乐透玩法 网易彩票app是真的吗 看4张牌的抢庄牛牛 重庆时时彩开奖记录