面試題-淺談JavaScript中的This指向問題

来源:https://www.cnblogs.com/peerless1029/archive/2018/11/16/9967098.html
-Advertisement-
Play Games

各位小伙伴在面試中被面試官問道this指向問題一定不少吧,同時還被問道apply,call和bind的用法區別,現在,就來簡單的聊一聊this到底指向何方。 1.基本概念 MDN的官方解釋:與其他語言相比,函數的 this 關鍵字在 JavaScript 中的表現略有不同,此外,在嚴格模式和非嚴格模 ...


  各位小伙伴在面試中被面試官問道this指向問題一定不少吧,同時還被問道apply,call和bind的用法區別,現在,就來簡單的聊一聊this到底指向何方。

1.基本概念

MDN的官方解釋:與其他語言相比,函數的 this 關鍵字在 JavaScript 中的表現略有不同,此外,在嚴格模式和非嚴格模式之間也會有一些差別。在絕大多數情況下,函數的調用方式決定了this的值。this不能在執行期間被賦值,並且在每次函數被調用時this的值也可能會不同。

簡而言之:

  1.this指向的對象稱為函數的上下文對象context;  

  2.this的指向取決於函數被調用方式 

不管函數怎麼調用的天花亂墜,我們只要記住這幾點即可清晰的找出this的指向。

2.小試牛刀

function foo(){
  console.log(this);
}

面試官問你this指向哪裡,當然大聲回答不知道,原因:誰調用指向誰,函數都沒被調用,確實不知道指向。

 小結:直接通過函數名來調用函數,this指向全局變數window;通過對象.函數名調用函數,this指向該對象。

3.DOM對象調用函數時this的指向問題

1.通過選擇器選擇元素加事件屬性來綁定事件,this指向該DOM對象,例子如下:

document.getElementById('btn').onclick=function(){
    console.log('click'); //click
    console.log(this); //<button id="btn">button</button>
  }

 2.直接在DOM標簽中寫事件,this指向window,我們可以通過吧this作為參數傳入方法中再使用,例子如下

html:
<button onclick="modify()">add</button>
<span id="count">0</span>
<button onclick="modify()">reduce</button>

script:
// 操作方法
  function modify(){
    console.log(this); //window
  }

因為這個時候是直接調用方法的,所以this指向全局window對象,那麼問題來了,我們想判斷我們點擊的是哪一個按鈕,應該怎麼做呢,我們可以把this的值作為參數傳入方法中再使用,例子如下。

html:
<button onclick="modify(this)">add</button>
<span id="count">0</span>
<button onclick="modify(this)">reduce</button>

script:
// 操作方法
  function modify(_this){
    console.log(_this); 
// <button onclick="modify(this)">add</button>
// <button onclick="modify(this)">reduce</button>
  }

4.對象中this的指向問題

先看一個簡單的例子:

var a=1;
function printA(){
  console.log(this.a);
}
var obj={
  a:2,
  foo:printA,
  bar:function(){
    printA();
  }
}

obj.foo(); //2
obj.bar(); //1
var foo=obj.foo;
foo(); //1

我們定義了一個全局變數a和一個列印a的全局變數方法,之後又定義了一個obj對象,其中包含a屬性和foo,bar兩個方法。當我們調用obj.foo()列印了2,調用obj.bar()列印了1.

分析:

不管printA在哪裡定義的,我們this的指向只取決於被誰調用的。在obj.foo(),foo的屬性值為printA,被obj直接調用,所以this指向obj,this.a就是obj.a=2了;

當我們調用obj.bar()時,bar的屬性值為function(){printA()},沒有明確哪個對象來調用printA方法,this預設指向全局對象window,所以this.a=window.a=1;

第三種情況我們把obj.foo值賦予了foo變數,在調用的時候就相當於是window.foo()了,列印1。

小結:this的指向不是函數聲明是綁定的,而是在函數運行過程中動態綁定的。

5.改變this的指向方法:applay call bind

話不多話:寫了一個例子,大家先看,萬一比喻不恰當,大家能理解其中意思即可

var liLei={
  name:'liLei',
  money:10,
  buyPen:function(){
    this.money=this.money-1;
    console.log(this.name+" have money:"+this.money)
  }
}

var hanMeiMei={
  name:'hanMeiMei',
  money:20,
  buyPan:function(){
    this.money=this.money-2;
    console.log(this.name+" have money:"+this.money)
  }
}

liLei.buyPen(); // liLei have money:9
hanMeiMei.buyPan(); //hanMeiMei have money:18 

例子很好理解,輸出的結果相信大家也能看得明白,哪天,韓梅梅想買一個盆,她買不了,因為她還沒有這個方法,她一想:我沒有這個方法,但是李雷有啊,我打電話給李雷把錢他讓他幫我買啊;後來李雷想買一個盤,實現方法也是如此。那麼,在代碼中如何實現呢?

JavaScript有好幾個方法可以實現:call,apply,bind。

call方法:
語法:call(thisObj,Object)
定義:調用一個對象的一個方法,以另一個對象替換當前對象。
說明:
call 方法可以用來代替另一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變為由 thisObj 指定的新對象。如果沒有提供 thisObj 參數,那麼 Global 對象被用作 thisObj。

liLei.buyPen.call(hanMeiMei); //hanMeiMei have money:19
hanMeiMei.buyPan.call(liLei); //liLei have money:8

apply方法:
語法:apply(thisObj,[argArray])
定義:應用某一對象的一個方法,用另一個對象替換當前對象。
說明:
如果 argArray 不是一個有效的數組或者不是 arguments 對象,那麼將導致一個 TypeError。如果沒有提供 argArray 和 thisObj 任何一個參數,那麼 Global 對象將被用作 thisObj, 並且無法被傳遞任何參數。

liLei.buyPen.apply(hanMeiMei); //hanMeiMei have money:19
hanMeiMei.buyPan.apply(liLei); //liLei have money:8

bind方法:

liLei.buyPen.bind(hanMeiMei)(); //hanMeiMei have money:19
hanMeiMei.buyPan.apply(liLei)(); //liLei have money:8

小結:三種方法的相同指出是:可以改變this的指向,不同之處是:apply接受的參數為一個數組,call接收的參數為一個個獨立的值;apply,call會直接調用方法,bind改變this的指向返回一個方法不調用。

註:有些低版本的瀏覽器不支持函數使用bind方法,我們在做瀏覽器相容時可以加以判斷,具體實現方法暫不贅述。

 

  以上就是個人對於this的指向問題的理解,我們只需記住一點:this指向-誰調用,指向誰。不得不說JavaScript真是個奇妙的世界,文中有紕漏不足的地方,歡迎指正。


 

參考資料:

MDN-this

傑瑞教育

外婆的彭湖灣

轉載請註明出處,謝謝!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 大數據已經成為時代發展的趨勢,很多人紛紛選擇學習大數據,想要進入大數據行業。大數據技術體系龐大,包括的知識較多,系統的學習大數據可以讓你全面掌握大數據技能。學習大數據需要掌握哪些知識?1、學習大數據首先要學習Java基礎怎樣進行大數據學習的快速入門?學大數據課程之前要先學習一種電腦編程語言。Jav ...
  • 歸檔文件過大,會導致資料庫出現異常,無法登陸。 1.D盤下新建一個delete_arch.txt文件 2.新建一個批處理文件deleArch.bat(把記事本的尾碼修改為.bat就行) 3.雙擊運行deleArch.bat就可以刪除歸檔日誌 4.可以把這個批處理添加到計劃任務中,定時執行(基本操作, ...
  • 現有資料庫使用字元集是GBK,做讀寫分離的時候,發現讀庫的資料庫安裝錯誤,使用了UTF8的字元集 需要把讀庫的字元集進行調整。 1.進入PLSQL查看下資料庫字元集 2.進入伺服器的命令行控制台,通過cmd進入 3.關閉資料庫 4.啟動資料庫掛載 5.使用資料庫追蹤 6.開啟限制會話模式 7. 8. ...
  • 什麼是二次排序 待排序的數據具有多個欄位,首先對第一個欄位排序,再對第一欄位相同的行按照第二欄位排序,第二次排序不破壞第一次排序的結果,這個過程就稱為二次排序 如何在mapreduce中實現二次排序 mapreduce的工作原理 MR的工作原理如下圖(如果看不清可右鍵新標簽頁查看): 圖片部分數據參 ...
  • 簡介 備份mysql資料庫一直是一個比較噁心的工作,主要就是備份的資料庫比較大實在是慢。最近開始使用xtrabackup來備份資料庫,速度上快了很多,尤其還原速度要快的多。下麵我將從安裝開始簡要介紹一下如何使用xtrabackup來備份資料庫。 定義:xtrabackup工具是percona公司用p ...
  • Category原理 - Category編譯之後的底層結構是 struct categroy_t,裡面存儲著分類對象方法、屬性、協議信息- 當程式運行時,通過runtime動態的將分類的方法、屬性、協議合併到一個大數組中- 底層使用的是二維數組進行存儲,比如:[[分類2方法列表],[分類1方法列表 ...
  • 一,效果圖。 二,代碼。 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>javascript 用法</title> </head> <body> <!--使用 window.alert()--> <h1>我的第一個頁面</h1 ...
  • 一、前言 上周末的時候,準備試試將 ASP.NET Core 的項目部署到 CentOS 伺服器上,結果在一個接一個坑裡面跳,最後 Supervisor 守護程式還是有問題,於是,採用重裝系統大招,結果,碰巧趕上 aspnetcore 的一個 bug( Missing package dotnet- ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...