javascript 之this指針-11

来源:https://www.cnblogs.com/CandyManPing/archive/2018/01/12/8276155.html
-Advertisement-
Play Games

前言 在《javascript 之執行環境-08》文中說到,當JavaScript代碼執行一段可執行代碼時,會創建對應的執行上下文(execution context)。對於每個執行上下文,都有三個重要屬性: 變數對象(Variable object,VO) 作用域鏈(Scope chain) th ...


 前言

在《javascript 之執行環境-08》文中說到,當JavaScript代碼執行一段可執行代碼時,會創建對應的執行上下文(execution context)。對於每個執行上下文,都有三個重要屬性:

  • 變數對象(Variable object,VO)
  • 作用域鏈(Scope chain)
  • this

  JavaScript中的this跟其他語言有些不一樣,比如Java .net語言中的this是在代碼的執行階段是不可變的,而JavaScript的this是在調用階段進行綁定。也因為這一性質給了this很大的靈活性,即當函數在不同的調用方式下都可能會導致this的值不同;

定義

  this 對象是在運行時基於函數的執行環境綁定的,跟函數的調用位置有關而不是聲明的位置;可以理解為this是在函數調用階段綁定,也就是執行上下文創建的階段進行賦值,保存在變數對象中;

四種綁定規則

new 構造函數綁定,this指向新創建的對象

 1 function createPerson(){
 2        return new person();
 3     }
 4     function person() {
 5         this.name = "Joel";
 6         this.say=function(){
 7             console.log(p)
 8             console.log('hello' + this.name)
 9         }
10     }
11     var p = new person();
12     p.say();
13     console.log(p.name);//Joel
14     console.log('開始')
15     var t=createPerson();
16     t.say();

不管是直接new 還是通過function createPerson 函數返回的對象,this 都是指向了新創建出來的對象;

顯示綁定,this指向傳進去的對象

 1     //call() apply() bind() 顯示綁定
 2     window.color = "red";
 3     var Obj = { color: "blue" };
 4     function sayColor() {
 5         console.log(this.color);
 6     }
 7     sayColor();// red this window
 8     sayColor.call(this);//red
 9     sayColor.call(window);//red
10     sayColor.call(Obj);// blue 把this指針改為對象Obj
11     sayColor.apply(Obj);//blue 把this指針改為對象Obj
12     sayColor.bind(Obj)();//blue 把this指針改為對象Obj

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

1   function foo() {
2       console.log(this.a)
3     }
4    var a=2;
5     foo.call(null);//2
6     foo.call(undefined);//2

隱士綁定

以對象的方法形式調用,this指向當前這個對象

 1    function foo(){
 2         console.log(this)//{a: 2, name: "Joel", foo: ƒ}
 3         console.log(this.a)//2
 4     }
 5     var obj={
 6         a:2,
 7         name:'Joel',
 8         foo:foo
 9     };
10     obj.foo();

這時this指向當前obj對象,但是如果換種寫法會造成this 丟失問題。

 1     function foo(){
 2         console.log(this)//{a: 2, name: "Joel", foo: ƒ}
 3         console.log(this.a)//2
 4     }
 5     var obj={
 6         a:2,
 7         name:'Joel',
 8         foo:foo
 9     };
10     obj.foo();
11     //this 丟失的問題
12     var t= obj.foo;
13     t(); //window undefined

變數t此時保存的是函數的引用跟obj已經沒有關係,所以此時this指向window。

預設綁定 嚴格模式下this 綁定到undefined,否則綁定到全局對象 window

 1   function foo(){
 2         console.log(this)//window
 3         console.log(this.a)//Joel
 4     }
 5     var a='Joel';
 6     foo();
 7 
 8     //嚴格模式
 9     function fo(){
10         'use strict'  //嚴格模式
11         console.log(this)//undefined
12         console.log(this.b)//報錯 Cannot read property 'b' of undefined
13     }
14     var b='Joel';
15     fo();

以上是基本的this綁定規則,其中new、顯示綁定很容易判斷,其中比較容易錯的是容易把預設綁定誤認為是隱士綁定 如匿名函數、閉包、函數當做參數等;

獨立調用:this 指向window

 1   var name='Joel',age=12;
 2     function say(){
 3         function say1(){
 4             console.log(this.name);//window
 5             function say2(){
 6                 name+='-l'
 7                 console.log(this.name);//window
 8             }
 9             say2()
10         }
11         say1();
12     }
13     say();
14 
15     //匿名函數
16     (function(){
17        console.log(this.name)
18     })()

function 當做參數傳遞其實跟獨立調用一樣的原理

 1 function foo() {
 2         console.log(this)//window
 3         console.log(this.a)//oops global
 4     }
 5     function doFoo(fn) {
 6         console.log(this);//window
 7         fn();//類似與 foo()
 8     }
 9     var obj = {
10         a: 2,
11         foo: foo
12     }
13     var a = 'oops global';
14     doFoo(obj.foo);

同理setTimeout 也是一樣

 1  var obj = {
 2         a: 2,
 3         foo: function() {
 4             console.log(this); 
 5         },
 6         foo2: function() {
 7             console.log(this);   //this 指向 obj 
 8             setTimeout(this.foo, 1000);   // this 指向 window 
 9         }
10     }
11     var a = 'oops global';
12     obj.foo2();

閉包中的this

 1     var name = "Joel";
 2     var obj = {
 3         name: "My object",
 4         getName: function() {
 5             // var that = this;   // 將getNameFunc()的this保存在that變數中
 6             return function() {
 7                 return this.name;
 8             };
 9         }
10     }
11     console.log(obj.getName()());   // "Joel"

這裡的雖然是對象的方法形式調用obj.getName(),在getName中的this是指向obj,但是返回的匿名函數中的this 為什麼是window呢?

把最後的一句拆成兩個步驟執行:

1 var t=obj.getName();
2 t();

是不是有點像在獨立調用呢?如果需要訪問obj中的name,只需要把this對象緩存起來,在匿名函數中訪問即可,把var that=this;去掉註釋即可;

總結

  • this 是變數對象的一個屬性,是在調用時被綁定的,跟函數的調用位置有關而不是聲明的位置;
  • 找到調用位置,根據綁定規則來分析this 綁定;
  • 預設綁定嚴格模式下this 綁定到undefined,否則綁定到全局對象 window;

思考題

 1     var length = 5;
 2     var obj = {
 3         foo: function (fn) {
 4             console.log(this.length); // this => obj
 5             fn(); // this => window
 6             arguments[0](); // this => arguments
 7             var bar = arguments[0];
 8             bar(); // this => window
 9         },
10         length: 10
11     }
12     var fn = function () {
13         console.log(this.length);
14     }
15     obj.foo(fn);
16     //10, 5, 1, 5

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

-Advertisement-
Play Games
更多相關文章
  • 看不清的朋友右鍵保存或者新視窗打開哦!喜歡我可以關註我,還有更多前端思維導圖筆記 ...
  • 看不清的朋友右鍵保存或者新視窗打開哦!喜歡我可以關註我,還有更多前端思維導圖筆記 ...
  • 看不清的朋友右鍵保存或者新視窗打開哦!喜歡我可以關註我,還有更多前端思維導圖筆記 ...
  • 1.效果圖 2.源代碼 html css ...
  • 我們在操作html中的節點的時候,第一步就需要獲取到對應節點(元素),才能有後續的操作。獲取節點的方式有很多 1、document.getElementById(‘id值’) 通過id精確的選中某一個節點 說明通過document對象,根據id獲取某個精確的節點對象(獲取id值為mydiv1的節點) ...
  • 1.javaScript的基本結構:<script type="text/Javascript"> js語句 </script> 2..嵌入網頁的3種方法 1.在<script>標簽里直接寫 2.使用外部js文件,<script>標簽的src屬性,導入文件 3.直接在html里 列如 <input ...
  • 小點心,顧名思義,開箱即食,拿來即用。彈窗就無需多說了,幾乎所有存在交互的頁面都會用到,一個頁面上甚至會有 N 多個彈窗。彈彈彈,彈出魚尾紋。如果從面向對象的角度去看,把彈窗看成一個類想必是極好的,與之綁定的DOM塊是它的屬性,打開和關閉是它的方法,而且這樣可以實現彈窗樣式和邏輯的分離。 ...
  • 在做宣傳品發放系統時,需求要把資料庫查詢的記錄生成表單並轉存excel文件。 在轉存的EXCEL文件中文顯示亂碼,表格和其他字元正常,檢查後發現是創建EXCEL文件打開模式不對 之前: myfile = fs.CreateTextFile(filename,true) 之後: myfile = fs ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...