欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript中this綁定規(guī)則你理解了嗎

 更新時(shí)間:2023年07月16日 10:49:14   作者:南墨  
JavaScript中的this是一個(gè)非常重要的概念,也是一個(gè)令新手開(kāi)發(fā)者甚至有些不深入理解的多年經(jīng)驗(yàn)開(kāi)發(fā)者都會(huì)感到困惑的概念,如果你希望自己能夠使用this編寫(xiě)更好的代碼或者更好理解他人的代碼,就跟隨小編一起理解一下this吧

前言

JavaScript 中的 this 是一個(gè)非常重要的概念,也是一個(gè)令新手開(kāi)發(fā)者甚至有些不深入理解的多年經(jīng)驗(yàn)開(kāi)發(fā)者都會(huì)感到困惑的概念。

如果你希望自己能夠使用 this 編寫(xiě)更好的代碼或者更好理解他人的代碼,那就跟著我一起理解一下this吧。

要理解this的原因

我們先搞清楚為什么要理解 this 的,再去學(xué)習(xí)它。

學(xué)習(xí) this 可以幫助我們更好地理解代碼的上下文和執(zhí)行環(huán)境,從而編寫(xiě)更好的代碼。

例1

function speakfullName(){
    console.log(this.firstname + this.lastname)
}
var firstname = '南'
var lastname = '墨'
const gril = {
    firstname: '黎',
    lastname: '蘇蘇',
    speakfullName,
}
const boy = {
    firstname: '澹臺(tái)',
    lastname: '燼',
    speakfullName,
}
 gril.speakfullName(); // 輸出: 黎蘇蘇
 boy.speakfullName(); // 輸出: 澹臺(tái)燼
 speakfullName(); // 輸出: 南墨

在這個(gè)例子中,如果你沒(méi)理解 this 的用法,那么閱讀這段代碼就會(huì)覺(jué)得奇怪,為什么同一個(gè)函數(shù)會(huì)輸出不同的結(jié)果。之所以奇怪,是因?yàn)槟悴恢浪纳舷挛牡降资鞘裁础?/p>

學(xué)習(xí) this 可以幫助我們編寫(xiě)更具可重用性和可維護(hù)性的代碼

在例1中可以在不同的上下文中使用 this,不用針對(duì)不同版本寫(xiě)不同的函數(shù)。當(dāng)然不使用 this,也是可以的。

例2

function speakfullName(person){
    console.log(person.firstname + person.lastname)
}
const gril = {
    firstname: '黎',
    lastname: '蘇蘇',
}
const boy = {
    firstname: '澹臺(tái)',
    lastname: '燼',
}
speakfullName(gril); // 黎蘇蘇 
speakfullName(boy); // 澹臺(tái)燼

雖然目前這段代碼沒(méi)有問(wèn)題,如果后續(xù)使用的模式越來(lái)越復(fù)雜,那么這樣的顯示傳遞會(huì)讓代碼變得難以維護(hù)和重用,而this的隱式傳遞會(huì)顯得更加優(yōu)雅一些。因此,學(xué)習(xí)this可以幫助我們編寫(xiě)更具有可重用性和可維護(hù)性的代碼。

接下來(lái)我們開(kāi)始正式全面解析 this

解析 this

我相信大家多多少少都理解一些 this 的用法,但可能不夠全面,所以接下來(lái)我們就全面性的理解 this。

很多人可能認(rèn)為this 寫(xiě)在哪里就是指向所在位置本身,如下代碼:

var a = 2
function foo (){
   var a = 1
   console.log(this.a)
}
foo();

有些人認(rèn)為會(huì)輸出1,實(shí)際是輸出2,這就是不夠理解 this 所產(chǎn)生的的誤會(huì)。

this的機(jī)制到底是什么樣的呢?

其實(shí)this不是寫(xiě)在哪里就被綁定在哪里,而是代碼運(yùn)行的時(shí)候才被綁定的。也就是說(shuō)如果一個(gè)函數(shù)中存在this,那么this到底被綁定成什么取決于這個(gè)函數(shù)以什么樣的方式被調(diào)用。

既然已經(jīng)提出了這樣一個(gè)機(jī)制,那我們?cè)撊绾胃鶕?jù)這個(gè)機(jī)制,去理解和判斷this被綁定成什么呢?

下面我們繼續(xù)介紹這個(gè)機(jī)制的基本原理。

調(diào)用位置

上面說(shuō)過(guò),函數(shù)的調(diào)用位置會(huì)影響this被綁定成什么了,所以我們需要知道函數(shù)在哪里被調(diào)用了。

我們回頭去看一下 例1,來(lái)理解什么是調(diào)用位置:

// ...
 gril.speakfullName(); // 輸出: 黎蘇蘇
 boy.speakfullName(); // 輸出: 澹臺(tái)燼
 speakfullName(); // 輸出: 南墨

同一個(gè)函數(shù) speakfullName, 在不同的調(diào)用位置,它的輸出就不一樣。

gril 對(duì)象中調(diào)用時(shí),輸出了黎蘇蘇,在 boy 對(duì)象中調(diào)用時(shí),輸出了澹臺(tái)燼,在全局調(diào)用時(shí)輸出了南墨。

當(dāng)然例子中的調(diào)用位置是非常容易看出來(lái)的。所以我們接下來(lái)繼續(xù)講解在套多層的情況下如何找到調(diào)用位置。

我們要找到調(diào)用位置就要分析調(diào)用棧。

看下簡(jiǎn)單例子:

function baz() {
  // 當(dāng)前調(diào)用棧:baz
  console.log('baz')
  bar(); // bar 調(diào)用的位置
}
function bar() {
  // 當(dāng)前調(diào)用棧:baz-bar
  console.log('bar')
  foo(); // foo 調(diào)用的位置
}
function foo() {
  // 當(dāng)前調(diào)用棧:baz-bar-foo
  console.log('foo')
}
baz() // baz的調(diào)用位置

其實(shí)調(diào)用棧就是調(diào)用位置的鏈條,就像上面代碼例子中所分析的一樣。不過(guò)在一些復(fù)雜點(diǎn)的代碼中,這樣去分析很容易出錯(cuò)。所以我們可以用現(xiàn)代瀏覽器的開(kāi)發(fā)者工具幫助我們分析。

比如上例中,我們想找到 foo 的調(diào)用位置,在 foo 中第一行輸入debugger。

// ...
function foo() {
  debugger
  // ...
}
// ...

或者打開(kāi)瀏覽器的開(kāi)發(fā)者工具到源代碼一欄找到,foo的代碼的第一行打一個(gè)斷點(diǎn)也行,如下圖:

接著在源代碼一欄,找到調(diào)用堆棧的foo的下一個(gè)就是bar,bar就是foo的調(diào)用位置。

綁定規(guī)則

接下來(lái)看看調(diào)用位置如何決定this被綁定成什么,并且進(jìn)行總結(jié)。

默認(rèn)規(guī)則

第一種情況是函數(shù)最經(jīng)常被調(diào)用的方式,函數(shù)被單獨(dú)調(diào)用??匆韵吕樱?/p>

var name = '澹臺(tái)燼'
function fn(){
    console.log('我是' + this.name)
}
fn() // 我是澹臺(tái)燼

運(yùn)行fn后,最終輸出了 我是澹臺(tái)燼。眾所周知,上例中的 name 是全局的變量,這樣說(shuō)明了fn中的 this.name 被綁定成了全局變量name。因此,this指向了全局對(duì)象。

因?yàn)樵谏侠拇a片段中,foo的調(diào)用位置是在全局中調(diào)用的,沒(méi)有其他任何修飾, 所以我們稱之為默認(rèn)規(guī)則。

使用了嚴(yán)格模式的話,上例代碼會(huì)出現(xiàn)什么樣的情況呢?

var name = '澹臺(tái)燼'
function sayName(){
    "use strict"
    console.log(this) // (1)
    console.log('我是' + this.name) // (2)
}
fn() 
// undefined 
// TypeError: cannot read properties of undefined (reading 'name') as sayName

可以看出來(lái)(1)也就是this,輸出了undefiend 所以(2)就直接報(bào)錯(cuò)了。

因此我們可以得出默認(rèn)規(guī)則的結(jié)論:在非嚴(yán)格模式下,this默認(rèn)綁定成全局對(duì)象,在嚴(yán)格模式下,this 被綁成 undefined

隱式綁定

這條規(guī)則需要我們?nèi)ヅ袛嗪瘮?shù)的調(diào)用是否有上下文對(duì)象,也就是說(shuō)函數(shù)調(diào)用的時(shí)候前面是否跟了一個(gè)對(duì)象,舉個(gè)例子看下。

function sayName() {
    console.log(`我是` + this.name)
}
var person = {
    name: '澹臺(tái)燼',
    sayName,
}
person.sayName(); // 我是澹臺(tái)燼

在這個(gè)例子中, sayName 前面有一個(gè) person,也就是說(shuō) sayName 函數(shù)有一個(gè)上下文對(duì)象person, 這樣調(diào)用 sayName 的時(shí)候,函數(shù)中 this 被綁定成了person,因此 this.nameperson.name 是一樣的。

在觀察隱式綁定的時(shí)候,有兩種值得我們注意的情況:

如果說(shuō)一個(gè)函數(shù)是通過(guò)對(duì)象的方式調(diào)用時(shí),只有最后一個(gè)對(duì)象起到上下文的作用。 例3:

function sayName() {
    console.log(`我是` + this.name)
}
var child = {
    name: '澹臺(tái)燼',
    sayName,
}
var father = {
    name: '澹臺(tái)無(wú)極',
    child,
}
father.child.sayName(); // 我是澹臺(tái)燼

這個(gè)例子中,是通過(guò)一個(gè)對(duì)象鏈調(diào)了sayName,沒(méi)有輸出我是澹臺(tái)無(wú)極,而是我是澹臺(tái)燼。因此 this 指向了child 對(duì)象,說(shuō)明this 最終綁定為對(duì)象鏈的最后一個(gè)對(duì)象。

隱式丟失的情況就是被隱式綁定的函數(shù)丟失綁定的上下文,轉(zhuǎn)而變成了應(yīng)用默認(rèn)綁定。

function sayName() {
    console.log(`我是` + this.name)
}
var person = {
    name: '澹臺(tái)燼',
    sayName,
}
var personSayName = person.sayName;
var name = '南墨'
pesonSayName() // '我是南墨'

雖然 personSayName 看起來(lái)是由 person.sayName 賦值的來(lái),擁有上下文對(duì)象person,但實(shí)際上 personSayName 被賦予的是 sayName 函數(shù)本身,因此此時(shí)的 personSayName其實(shí)是一個(gè)不帶修飾的函數(shù), 所以說(shuō)會(huì)被認(rèn)為是默認(rèn)綁定。

顯示綁定

隱式綁定是通過(guò)一個(gè)看起來(lái)不經(jīng)意間的上下文的形式去綁定的。

那也當(dāng)然也有通過(guò)一個(gè)明顯的上下文強(qiáng)制綁定的,這就是顯示綁定

javaScript 中,要是使用顯示綁定,就要通過(guò) callapply方法去強(qiáng)制綁定上下文了

這兩個(gè)方法的使用方法是什么樣的呢? callapply的第一個(gè)參數(shù)的是一樣的,就是傳入一個(gè)我們想要給函數(shù)綁定的上下文。

來(lái)看一下下面的例子

function sayName () {
 console.log(this.name)
}
var person = {
   name: 南墨
}
sayName.call(person) // 南墨

看到?jīng)]? 我們通過(guò)call的方式,將函數(shù)的上下文綁定為了 person,因此打印出了 南墨

使用了 call 綁定也會(huì)有綁定丟失的情況,所以我們需要一種保證在我意料之內(nèi)的辦法, 可以改造顯示綁定,思考如下代碼:

function sayName() {
 console.log(this.name)
}
var person = {
 name: 南墨
}
function sayNanMo() {
 sayName.call(person);
}
sayNanMo() // 南墨
setTimeout(sayNanMo, 10000) // 南墨
sayNanMo.call(window) // 南墨

這樣一來(lái),不管怎么操作,都會(huì)輸出南墨,是我想要的結(jié)果

我們將 sayName.call(person) 放在的 sayNanMo 中,因此sayName 只能被綁定為我們想要綁定的 person。

我們可以將其寫(xiě)成可復(fù)用的函數(shù)

function bind(fn, obj) {
 return function() {
   fn.apply(obj, arguments)
 }
}

ES5 就提供了內(nèi)置的方法 Function.prototype.bind,用法如下:

function sayName() {
  console.log(this.name)
}
var person = {
  name: 南墨
}
sayName.bind(person)

new綁定

new 綁定也可以影響函數(shù)調(diào)用時(shí)的 this 綁定行為,我們稱之為new 綁定。

思考如下代碼:

function person(name) {
   this.name = name;
   this.sayName = function() {
     console.log(this.name)
   }
}
var personOne = new person('南墨')
personOne.sayName() // 南墨

personOne.sayName 能夠輸出南墨,是因?yàn)槭褂?new 調(diào)用 person 時(shí),會(huì)創(chuàng)建一個(gè)新的對(duì)象并將它綁定到 person 中的 this 上,所以personOne.sayName中的 this.name 等于外面的this.name。

規(guī)則之外

值得一提的是,ES6的箭頭函數(shù),它的this無(wú)法使用以上四個(gè)規(guī)則,而是而是根據(jù)外層(函數(shù)或者全局)作用域來(lái)決定this。

  function sayName () {
     return () => {
       console.log(this.name)
     }
  }
  var person1 = {
        name: 南墨
  }
  var person2 = {
      name: '澹臺(tái)燼'
  }
  sayName.call(person1)
  sayName.call(person1).call(person2) // 澹臺(tái)燼,如果是普通函數(shù)會(huì)輸南墨
}

總結(jié)

要想判斷一個(gè)運(yùn)行的函數(shù)中this的綁定,首先要找到函數(shù)調(diào)用位置,因?yàn)樗鼤?huì)影響this的綁定。然后使用四個(gè)綁定規(guī)則:new綁定、顯示綁定、隱式綁定、默認(rèn)規(guī)則 來(lái)判斷this的綁定。

到此這篇關(guān)于JavaScript中this綁定規(guī)則你理解了嗎的文章就介紹到這了,更多相關(guān)JavaScript this綁定規(guī)則內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 必備的JS調(diào)試技巧匯總

    必備的JS調(diào)試技巧匯總

    試想一下:出現(xiàn)了某個(gè)bug,有人用幾分鐘就搞定了,有人用了半天或者一天都找不到原因所在。你愿意當(dāng)前者還是后者呢?想當(dāng)前者的就請(qǐng)好好看完本篇文章吧。文中涉及較多Gif演示動(dòng)畫(huà)請(qǐng)注意。
    2016-07-07
  • js 動(dòng)態(tài)生成html 觸發(fā)事件傳參字符轉(zhuǎn)義的實(shí)例

    js 動(dòng)態(tài)生成html 觸發(fā)事件傳參字符轉(zhuǎn)義的實(shí)例

    下面小編就為大家?guī)?lái)一篇js 動(dòng)態(tài)生成html 觸發(fā)事件傳參字符轉(zhuǎn)義的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • 如何使用JS獲取當(dāng)前節(jié)點(diǎn)的兄弟/父/子節(jié)點(diǎn)

    如何使用JS獲取當(dāng)前節(jié)點(diǎn)的兄弟/父/子節(jié)點(diǎn)

    在日常的網(wǎng)頁(yè)開(kāi)發(fā)中,我們會(huì)遇到獲取節(jié)點(diǎn)的問(wèn)題,而js是寫(xiě)網(wǎng)頁(yè)的最基礎(chǔ)的語(yǔ)言,也是最常用的,這篇文章主要給大家介紹了關(guān)于如何使用JS獲取當(dāng)前節(jié)點(diǎn)的兄弟/父/子節(jié)點(diǎn)的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • 與iframe進(jìn)行跨域交互的解決方案(推薦)

    與iframe進(jìn)行跨域交互的解決方案(推薦)

    這篇文章主要介紹了與iframe進(jìn)行跨域交互的解決方案,本文通過(guò)實(shí)例代碼給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • javascript div 遮罩層封鎖整個(gè)頁(yè)面

    javascript div 遮罩層封鎖整個(gè)頁(yè)面

    在客戶端瀏覽器中,可以在某個(gè)時(shí)機(jī)使用javascript把一個(gè)div作為遮罩層,來(lái)封鎖整個(gè)頁(yè)面。
    2009-07-07
  • 微信小程序?qū)崿F(xiàn)手勢(shì)滑動(dòng)效果

    微信小程序?qū)崿F(xiàn)手勢(shì)滑動(dòng)效果

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)手勢(shì)滑動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • JS設(shè)置自定義快捷鍵并實(shí)現(xiàn)圖片上下左右移動(dòng)

    JS設(shè)置自定義快捷鍵并實(shí)現(xiàn)圖片上下左右移動(dòng)

    這篇文章主要介紹了JS設(shè)置自定義快捷鍵并實(shí)現(xiàn)圖片上下左右移動(dòng),文中通過(guò)使用自定義熱鍵或者使用鍵盤(pán)上下左右鍵移動(dòng)圖片,以此來(lái)實(shí)現(xiàn)此功能,需要的朋友可以參考下
    2019-10-10
  • Javascript實(shí)現(xiàn)前端簡(jiǎn)單的路由實(shí)例

    Javascript實(shí)現(xiàn)前端簡(jiǎn)單的路由實(shí)例

    本文將使用javascript實(shí)現(xiàn)一個(gè)極其簡(jiǎn)單的路由實(shí)例。WEB開(kāi)發(fā)中路由概念并不陌生,我們接觸到的有前端路由和后端路由。后端路由在很多框架中是一個(gè)重要的模塊,同樣前端路由在單頁(yè)面應(yīng)用也很常見(jiàn),它使得前端頁(yè)面體驗(yàn)更流暢。
    2016-09-09
  • js完美解決IE6不支持position:fixed的bug

    js完美解決IE6不支持position:fixed的bug

    關(guān)于IE6,雖然它已被微軟拋棄很久了,但是由于大天朝的特殊行情(盜版)對(duì)于前端工程師來(lái)說(shuō),解決IE6兼容position:fixed的問(wèn)題顯得很重要。特別是你需要用到頭尾懸停調(diào)用的時(shí)候
    2015-04-04
  • 解決ueditor jquery javascript 取值問(wèn)題

    解決ueditor jquery javascript 取值問(wèn)題

    這篇文章主要介紹了解決ueditor jquery javascript 取值問(wèn)題,需要的朋友可以參考下
    2014-12-12

最新評(píng)論