JavaScript之撲朔迷離的this

来源:https://www.cnblogs.com/gerry2019/archive/2019/03/17/10546752.html
-Advertisement-
Play Games

JavaScript這門語言中,最令人迷惑的地方有三個,閉包、this、原型。針對大多數人,可以利用詞法作用域等避開this的坑,但是我們不能一直生活在舒適區,要敢於打破砂鍋問到底,對我們來說也是一種提升。 一、一般對this關鍵字的誤解: 1、this指向函數自身 2、this指向函數聲明的詞法作 ...


  JavaScript這門語言中,最令人迷惑的地方有三個,閉包、this、原型。針對大多數人,可以利用詞法作用域等避開this的坑,但是我們不能一直生活在舒適區,要敢於打破砂鍋問到底,對我們來說也是一種提升。

  一、一般對this關鍵字的誤解:

    1、this指向函數自身

    2、this指向函數聲明的詞法作用域

  我們可以看以下一段代碼:

 1 function test() {
 2             test.a = 1;
 3             this.a = 2;
 4             console.log(test.a);
 5             console.log(this.a);
 6             console.log(test.a === this.a);
 7         }
 8 
 9         test();
10         console.dir(test);

  在上面這段代碼中,我們在全局聲明一個方法test,給test中的a屬性賦值1,當前方法中的this中的a屬性賦值2,加入this指向函數自身,那麼test.a === this,a並且都等於2.

下麵我們來看下這段代碼的運行結果:

  

  從上可以看出,scopes為全局作用域window,this也指向這裡,雖然函數本身也是一個對象,但是this並不指向這裡。

  有一點我們一定要記住,this是在運行時進行綁定的,並不是在編寫時綁定的,它的上下文取決於函數調用時的各種條件。this的綁定和函數聲明的位置沒有任何關係,只取決於函數的調用方式。

  既然this是在運行時綁定的,那我們有沒有辦法改變當前this的綁定,使其不指向window,而指向方法test呢?答案是肯定的,我們可以藉助一些強制綁定方法,如call、apply、bind來改變this的指向,我們可以將代碼改成下麵這種方式:

 1 function test() {
 2             test.a = 1;
 3             this.a = 2;
 4             console.log(test.a);
 5             console.log(this.a);
 6             console.log(test.a === this.a);
 7         }
 8 
 9         test.call(test);
10         console.dir(test);

  運行結果如下:

   接下來我們看下this是否指向函數聲明的詞法作用域,以下有段比較有意思的代碼:

 1 function parent() {
 2             var a = 2;
 3 
 4             function child() {
 5                 console.log(this.a)
 6             }
 7             child();
 8 
 9         }
10         parent();

  假如this指向函數的詞法作用域,那麼child方法中的this.a應該是存在,實際上的執行結果如下,child中的this指向仍為window:

 

  實際上,在JavaScript內部,作用域確實和對象類似,可見的標識符都是它的屬性。但是作用域“對象”無法通過JavaScript代碼訪問,它存在JavaScript引擎內部。所以每當你想要把this和詞法作用域的查找混合使用時,一定要提醒自己,這是無法實現的。

   二、this的綁定規則

    this的綁定規則大致分為以下幾類:

      2.1 預設綁定

      2.2 隱式綁定

      2.3 顯式綁定

      2.4 new綁定

    2.1 預設綁定

      上述示例中this的指向是指向window的,他們都有一個共同的特征,不帶任何修飾的函數引用進行調用的,因此只能使用預設綁定,無法應用其他規則

    2.2 隱式綁定

      隱式綁定首先需要考慮的規則就是調用位置是否有上下文對象,或者說是否被某個對象擁有或包含,例如:

  這裡的this就是指向對象obj。還有類似一些DOM事件的綁定,document.getElementById('xxx').addEventListener('click', function(){xxx});回調方法中的this是指向選擇器選中的元素的。這種情況下可以簡單的理解為this指向調用方法.前面的那個對象。

  2.3 顯式綁定

   顯示綁定在開發過程中運用的比較多,藉助於這些顯式綁定方法,可以直接改變當前方法的this指向,使得js語言非常的靈活。主要有call、apply和bind三種,基本使用如下:

 1  function sum() {
 2             console.log(this.a + this.b);
 3         }
 4         var obj1 = {
 5             a: 1,
 6             b: 2
 7         };
 8         var test = sum.bind(obj1);
 9         sum.call(obj1); //3
10         sum.apply(obj1); //3
11         test(); //3

  註意事項:

    call && apply第一個參數接受的是this對象,call第二個參數以後可以接受字元串形式的參數,apply接受的是一個類數組/數組參數

    將null || undefined作為this的綁定對象傳入call/apply/bind時,這些值在調用時會被忽略,實際應用的是預設綁定規則

  2.4 new綁定

    JavaScript語言中的new操作符和其他面向對象語言中的new操作符不大一樣,因為在JavaScript中沒有對象的概念。所有的函數都可以使用new來調用,new的調用又稱為構造函數調用。在構造函數調用過程中,會自動執行下麵的操作。

  1、創建(或者說構造)一個全新的對象

  2、這個對象會被執行[[Prototype]]連接

  3、這個新對象會綁定到函數調用的this

  4、如果函數沒有返回其他對象,那麼new表達式中的函數調用會自動返回這個新對象

  構造函數也是js中常用的一種設計模式,如以下代碼:

 1 function Test(a, b) {
 2             this.a = a;
 3             this.b = b;
 4             this.add = function() {
 5                 debugger;
 6                 console.log(this.a + this.b);
 7             }
 8         }
 9         var cc = new Test(1, 2);
10         cc.add();
11         console.log(cc);

  在new調用過程中,返回了一個新對象,並且該對象的this指向Test;

  如有問題,煩請及時指出,謝謝!


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

-Advertisement-
Play Games
更多相關文章
  • boostrap中模態框顯示在陰影之下 出現這種情況的原因我開始也搞了很久,問題出現在哪裡呢? 有事問百度,在百度上查了一下資料,他們主要的解決辦法:是 修改標簽的z-index屬性的值, 我試著改了z-index的值(z-index屬性要在設置了定位時才能用), 但是沒有解決這個問題, 後來又仔細 ...
  • 本篇文章是接著Spring Boot 入門(五):集成 AOP 進行日誌管理寫的,主要集成了樹形圖,在部門列表或者許可權列表中,樹形圖經常被用上。主要是根據相應的 API 憑藉 html 字元串 1.treetable 1 <link href="/plugins/treeTable/themes/d ...
  • 本文旨在介紹移動端h5分頁查詢實現 1.前端html 前端基於weui 樣式庫實現 參考http://jqweui.com/ 1 <div class="weui-search-bar" id="searchBar"> 2 <form class="weui-search-bar__form"> 3 ...
  • 父組件向子組件傳值 1. 組件實例定義方式,註意:一定要使用 屬性來定義父組件傳遞過來的數據 2. 使用 或簡化指令,將數據傳遞到子組件中: 子組件向父組件傳值 1. 原理:父組件將方法的引用,傳遞到子組件內部,子組件在內部調用父組件傳遞過來的方法,同時把要發送給父組件的數據,在調用方法的時候當作參 ...
  • vue+element 文件操作 作者:一粒塵土 時間:2019 3 17 註:以下操作針對 vue cli 目錄 "使用" "組件常用參數" "組件常用方法" "上傳文件" "上傳文件格式限制" "回顯文件" "下載文件" "刪除文件" 使用 使用npm安裝Element ui 依賴 配置vue中 ...
  • 參考鏈接: http://www.w3school.com.cn/xmldom/met_document_createelement.asp(createElement() 方法) http://www.w3school.com.cn/jsref/prop_option_index.asp(HTML ...
  • 當前版本v16.8.4 裝載過程(組件第一次在DOM樹中渲染的過程): constructor(常用) getInitialState(v16.0已廢棄) getDefaultProps(v16.0已廢棄) componentWillMount(v17.0中將被棄用) getDerivedState ...
  • 概述:jQuery是我們最常用的js庫,對於事件的綁定也是有很多種,on、one、live、bind、delegate等等,接下來我們逐一來進行講解。 本片文章中事件所帶的為版本號,例:v1.7+為1.7版本以上才有,v3.0 為3.0版本後不推薦使用,特此聲明。 本文參考了 w3school 事件 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...