日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
一文讀懂JavaScript中的this關(guān)鍵字

this 是一個令無數(shù) JavaScript 編程者又愛又恨的知識點(diǎn)。它的重要性毋庸置疑,然而真正想掌握它卻并非易事。希望本文可以幫助大家理解 this。

我們提供的服務(wù)有:做網(wǎng)站、成都網(wǎng)站建設(shè)、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、襄州ssl等。為1000+企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的襄州網(wǎng)站制作公司

JavaScript 中的 this

JavaScript 引擎在查找 this 時不會通過原型鏈一層一層的查找,因?yàn)?this 完全是在函數(shù)調(diào)用時才可以確定的,讓我們來看下面幾種函數(shù)調(diào)用的形式。

1. Function Invocation Pattern

普通的函數(shù)調(diào)用,這是我們使用較多的一種, foo 是以單獨(dú)的變量出現(xiàn)而不是屬性。其中的 this 指向全局對象。

 
 
 
  1. function foo() { 
  2.   console.log(this) 
  3.  
  4. foo() // Window 

函數(shù)作為對象的方法調(diào)用,會通過 obj.func 或者 obj[func] 的形式調(diào)用。其中的 this 指向調(diào)用它的對象。

 
 
 
  1. const obj = { 
  2.   name: 'lxfriday', 
  3.   getName(){ 
  4.     console.log(this.name) 
  5.   } 
  6.  
  7. obj.getName() // lxfriday 

2. Constructor Pattern

通過 new Constructor() 的形式調(diào)用,其 this 會指向新生成的對象。

 
 
 
  1. function Person(name){ 
  2.   this.name = name 
  3.  
  4. const person = new Person('lxfriday') 
  5. console.log(person.name) // lxfriday 

3. Apply Pattern

通過 foo.apply(thisObj) 或者 foo.call(thisObj) 的形式調(diào)用,其中的 this 指向 thisObj。如果 thisObj 是 null 或者 undefined ,其中的 this 會指向全局上下文 Window(在瀏覽器中)。

掌握以上的幾種函數(shù)調(diào)用形式就基本可以覆蓋開發(fā)中遇到的常見問題了,下面我翻譯了一篇文章,幫助你更深入的理解 this。

如果你已經(jīng)使用過一些 JavaScript 庫,你一定會注意到一個特殊的關(guān)鍵字 this。

this 在 JavaScript 中很常見,但是有很多開發(fā)人員花了很多時間來完全理解 this 關(guān)鍵字的確切功能以及在代碼中何處使用。

在這篇文章中,我將幫助您深入了解 this 其機(jī)制。

在深入了解之前,請確保已在系統(tǒng)上安裝了 Node 。然后,打開命令終端并運(yùn)行 node 命令。

全局環(huán)境中的 this

this 的工作機(jī)制并不容易理解。為了理解 this 是如何工作的,我們將探索不同環(huán)境中的 this。首先我們從全局上下文開始。

在全局層面中,this 等同于全局對象,在 Node repl(交互式命令行) 環(huán)境中叫 global。

 
 
 
  1. $ node 
  2. > this === global 
  3. true 

但上述情況只出現(xiàn)在 Node repl 環(huán)境中,如果我們在 JS 文件中跑相同的代碼,我們將會得到不同的答案。

為了測試,我們創(chuàng)建一個 index.js 的文件,并添加下面的代碼:

 
 
 
  1. console.log(this === global); 

然后通過 node 命令運(yùn)行:

 
 
 
  1. $ node index.js 
  2. false  

出現(xiàn)上面情況的原因是在 JS 文件中, this 指向 module.exports,并不是指向 global。

函數(shù)中的 this

Function Invocation Pattern

在函數(shù)中 this 的指向取決于函數(shù)的調(diào)用形式。所以,函數(shù)每次執(zhí)行的時候,可能擁有不同的 this 指向。

在 index.js 文件中,編寫一個非常簡單的函數(shù)來檢查 this 是否指向全局對象:

 
 
 
  1. function fat() { 
  2.   console.log(this === global) 
  3. fat() 

如果我們在 Node repl 環(huán)境執(zhí)行上面的代碼,將會得到 true,但是如果添加 use strict 到首行,將會得到 false,因?yàn)檫@個時候 this 的值為 undefined。

為了進(jìn)一步說明這一點(diǎn),讓我們創(chuàng)建一個定義超級英雄的真實(shí)姓名和英雄姓名的簡單函數(shù)。

 
 
 
  1. function Hero(heroName, realName) { 
  2.   this.realName = realName; 
  3.   this.heroName = heroName; 
  4. const superman= Hero("Superman", "Clark Kent"); 
  5. console.log(superman); 

請注意,這個函數(shù)不是在嚴(yán)格模式下執(zhí)行的。代碼在 node 中運(yùn)行將不會出現(xiàn)我們預(yù)期的 Superman 和 Clark Kent ,我們將得到 undefined。

這背后的原因是由于該函數(shù)不是以嚴(yán)格模式編寫的,所以 this 引用了全局對象。

如果我們在嚴(yán)格模式下運(yùn)行這段代碼,會因?yàn)?JavaScript 不允許給 undefined 增加屬性而出現(xiàn)錯誤。這實(shí)際上是一件好事,因?yàn)樗柚刮覀儎?chuàng)建全局變量。

最后,以大寫形式編寫函數(shù)的名稱意味著我們需要使用 new 運(yùn)算符將其作為構(gòu)造函數(shù)來調(diào)用。將上面的代碼片段的最后兩行替換為:

 
 
 
  1. const superman = new Hero("Superman", "Clark Kent"); 
  2. console.log(superman); 

再次運(yùn)行 node index.js 命令,您現(xiàn)在將獲得預(yù)期的輸出。

構(gòu)造函數(shù)中的 this

Constructor Pattern

JavaScript 沒有任何特殊的構(gòu)造函數(shù)。我們所能做的就是使用 new 運(yùn)算符將函數(shù)調(diào)用轉(zhuǎn)換為構(gòu)造函數(shù)調(diào)用,如上一節(jié)所示。

進(jìn)行構(gòu)造函數(shù)調(diào)用時,將創(chuàng)建一個新對象并將其設(shè)置為函數(shù)的 this 參數(shù)。然后,從函數(shù)隱式返回該對象,除非我們有另一個要顯式返回的對象。

在 hero 函數(shù)內(nèi)部編寫以下 return 語句:

 
 
 
  1. return { 
  2.   heroName: "Batman", 
  3.   realName: "Bruce Wayne", 
  4. }; 

如果現(xiàn)在運(yùn)行 node 命令,我們將看到 return 語句將覆蓋構(gòu)造函數(shù)調(diào)用。

當(dāng) return 語句嘗試返回不是對象的任何東西時,將隱式返回 this。

方法中的 this

Method Invocation Pattern

當(dāng)將函數(shù)作為對象的方法調(diào)用時,this 指向該對象,然后將該對象稱為該函數(shù)調(diào)用的接收者。

在下面代碼中,有一個 dialogue 方法在 hero 對象內(nèi)。通過 hero.dialogue() 形式調(diào)用時,dialogue 中的 this 就會指向 hero 本身。這里,hero 就是 dialogue 方法調(diào)用的接收者。

 
 
 
  1. const hero = { 
  2.   heroName: "Batman", 
  3.   dialogue() { 
  4.     console.log(`I am ${this.heroName}!`); 
  5.   } 
  6. }; 
  7. hero.dialogue(); 

上面的代碼非常簡單,但是實(shí)際開發(fā)時有可能方法調(diào)用的接收者并不是原對象。看下面的代碼:

 
 
 
  1. const saying = hero.dialogue(); 
  2. saying(); 

這里,我們把方法賦值給一個變量,然后執(zhí)行這個變量指向的函數(shù),你會發(fā)現(xiàn) this 的值是 undefined。這是因?yàn)?dialogue 方法已經(jīng)無法跟蹤原來的接收者對象,函數(shù)現(xiàn)在指向的是全局對象。

當(dāng)我們將一個方法作為回調(diào)傳遞給另一個方法時,通常會發(fā)生接收器的丟失。我們可以通過添加包裝函數(shù)或使用 bind 方法將 this 綁定到特定對象來解決此問題。

call、apply

Apply Pattern

盡管函數(shù)的 this 值是隱式設(shè)置的,但我們也可以通過 call()和 apply() 顯式地綁定 this。

讓我們像這樣重組前面的代碼片段:

 
 
 
  1. function dialogue () { 
  2.   console.log (`I am ${this.heroName}`); 
  3. const hero = { 
  4.   heroName: 'Batman', 
  5. }; 

我們需要將hero 對象作為接收器與 dialogue 函數(shù)連接。為此,我們可以使用 call() 或 apply() 來實(shí)現(xiàn)連接:

 
 
 
  1. dialogue.call(hero) 
  2. // or 
  3. dialogue.apply(hero) 

需要注意的是,在非嚴(yán)格模式下,如果傳遞 null 或者 undefined 給 call 、 apply 作為上下文,將會導(dǎo)致 this 指向全局對象。

 
 
 
  1. function dialogue() { 
  2.   console.log('this', this) 
  3. const hero = { 
  4.   heroName: 'Batman', 
  5. console.log(dialogue.call(null)) 

上述代碼,在嚴(yán)格模式下輸出 null,非嚴(yán)格模式下輸出全局對象。

bind

當(dāng)我們將一個方法作為回調(diào)傳遞給另一個函數(shù)時,始終存在丟失該方法的預(yù)期接收者的風(fēng)險,導(dǎo)致將 this 參數(shù)設(shè)置為全局對象。

bind() 方法允許我們將 this 參數(shù)永久綁定到函數(shù)。因此,在下面的代碼片段中,bind 將創(chuàng)建一個新 dialogue 函數(shù)并將其 this 值設(shè)置為 hero。

 
 
 
  1. const hero = { 
  2.   heroName: "Batman", 
  3.   dialogue() { 
  4.     console.log(`I am ${this.heroName}`); 
  5.   } 
  6. }; 
  7. // 1s 后打印:I am Batman 
  8. setTimeout(hero.dialogue.bind(hero), 1000); 

注意:對于用 bind 綁定 this 之后新生成的函數(shù),使用 call 或者 apply 方法無法更改這個新函數(shù)的 this。

箭頭函數(shù)中的 this

箭頭函數(shù)和普通函數(shù)有很大的不同,引用阮一峰 ES6入門第六章中的介紹:

  • 函數(shù)體內(nèi)的 this 對象,就是定義時所在的對象,而不是使用時所在的對象;
  • 不可以當(dāng)作構(gòu)造函數(shù),也就是說,不可以使用 new 命令,否則會拋出一個錯誤;
  • 不可以使用 arguments 對象,該對象在函數(shù)體內(nèi)不存在。如果要用,可以用 rest 參數(shù)代替;
  • 不可以使用 yield 命令,因此箭頭函數(shù)不能用作 Generator 函數(shù);

上面四點(diǎn)中,第一點(diǎn)尤其值得注意。this 對象的指向是可變的,但是在箭頭函數(shù)中,它是固定的,它只指向箭頭函數(shù)定義時的外層 this,箭頭函數(shù)沒有自己的 this,所有綁定 this 的操作,如 call apply bind 等,對箭頭函數(shù)中的 this 綁定都是無效的。

讓們看下面的代碼:

 
 
 
  1. const batman = this; 
  2. const bruce = () => { 
  3.   console.log(this === batman); 
  4. }; 
  5. bruce(); 

在這里,我們將 this 的值存儲在變量中,然后將該值與箭頭函數(shù)內(nèi)部的 this 值進(jìn)行比較。node index.js 執(zhí)行時將會輸出 true。

那箭頭函數(shù)中的 this 可以做哪些事情呢?

箭頭函數(shù)可以幫助我們在回調(diào)中訪問 this??匆幌挛以谙旅鎸懙?counter 對象:

 
 
 
  1. const counter = { 
  2.   count: 0, 
  3.   increase() { 
  4.     setInterval(function() { 
  5.       console.log(++this.count); 
  6.     }, 1000); 
  7.   } 
  8. counter.increase(); 

運(yùn)行上面的代碼,會打印 NaN。這是因?yàn)?this.count 沒有指向 counter 對象。它實(shí)際上指向全局對象。

要使此計(jì)數(shù)器工作,可以用箭頭函數(shù)重寫,下面代碼將會正常運(yùn)行:

 
 
 
  1. const counter = { 
  2.   count: 0, 
  3.   increase () { 
  4.     setInterval (() => { 
  5.       console.log (++this.count); 
  6.     }, 1000); 
  7.   }, 
  8. }; 
  9. counter.increase (); 

類中的 this

類是所有 JavaScript 應(yīng)用程序中最重要的部分之一。讓我們看看類內(nèi)部 this 的行為。

一個類通常包含一個 constructor,其中 this 將指向新創(chuàng)建的對象。

但是,在使用方法的情況下,如果該方法以普通函數(shù)的形式調(diào)用,則 this 也可以指向任何其他值。就像一個方法一樣,類也可能無法跟蹤接收者。

我們用類重寫上面的 Hero 函數(shù)。此類將包含構(gòu)造函數(shù)和 dialogue() 方法。最后,我們創(chuàng)建此類的實(shí)例并調(diào)用該 dialogue 方法。

 
 
 
  1. class Hero { 
  2.   constructor(heroName) { 
  3.     this.heroName = heroName; 
  4.   } 
  5.   dialogue() { 
  6.     console.log(`I am ${this.heroName}`) 
  7.   } 
  8. const batman = new Hero("Batman"); 
  9. batman.dialogue(); 

constructor 中的 this 指向新創(chuàng)建的類實(shí)例。batman.dialogue() 調(diào)用時,我們將 dialogue() 作為 batman 接收器的方法調(diào)用。

但是,如果我們存儲對 dialogue() 方法的引用,然后將其作為函數(shù)調(diào)用,則我們將再次失去方法的接收者,而 this 現(xiàn)在指向 undefined。

為什么是指向 undefined 呢?這是因?yàn)?JavaScript 類內(nèi)部隱式以嚴(yán)格模式運(yùn)行。我們將 say() 作為一個函數(shù)調(diào)用而沒有進(jìn)行綁定。所以我們要手動的綁定。

 
 
 
  1. const say = batman.dialogue.bind(batman); 
  2. say(); 

當(dāng)然,我們也可以在構(gòu)造函數(shù)內(nèi)部綁定:

 
 
 
  1. class Hero { 
  2.   constructor(heroName) { 
  3.     this.heroName = heroName 
  4.     thisthis.dialogue = this.dialogue.bind(this) 
  5.   } 
  6.   dialogue() { 
  7.     console.log(`I am ${this.heroName}`) 
  8.   } 

加餐:手寫 call、apply、bind

call 和 apply 的模擬實(shí)現(xiàn)大同小異,注意 apply 的參數(shù)是一個數(shù)組,綁定 this 都采用的是對象調(diào)用方法的形式。

 
 
 
  1. Function.prototype.call = function(thisObj) { 
  2.   thisObjthisObj = thisObj || window 
  3.   const funcName = Symbol('func') 
  4.   const that = this // func 
  5.   thisObj[funcName] = that 
  6.   const result = thisObj[funcName](...arguments) 
  7.   delete thisObj[funcName] 
  8.   return result 
  9.  
  10. Function.prototype.apply = function(thisObj) { 
  11.   thisObjthisObj = thisObj || window 
  12.   const funcName = Symbol('func') 
  13.   const that = this // func 
  14.   const args = arguments[1] || [] 
  15.   thisObj[funcName] = that 
  16.   const result = thisObj[funcName](...[thisObj, ...args]) 
  17.   delete thisObj[funcName] 
  18.   return result 
  19.  
  20. Function.prototype.bind = function(thisObj) { 
  21.   thisObjthisObj = thisObj || window 
  22.   const that = this // func 
  23.   const outerArgs = [...arguments].slice(1) 
  24.   return function(...innerArgs) { 
  25.     return that.apply(thisObj, outerArgs.concat(innerArgs)) 
  26.   } 

分享標(biāo)題:一文讀懂JavaScript中的this關(guān)鍵字
本文鏈接:http://m.5511xx.com/article/coppoee.html