關於JavaScript中this的指向,你知曉幾分?請速來圍觀!

来源:https://www.cnblogs.com/colinliu666/archive/2019/02/15/10384874.html
-Advertisement-
Play Games

恢復內容開始 一、this是什麼東東? this是指包含它的函數作為方法被調用時所屬的對象。這句話理解起來跟卵一樣看不懂,但是如果你把它拆分開來變成這三句話後就好理解一點了。 1.包含它的函數 2.作為方法被調用時 3.所屬的對象 二、this的綁定規則 1、預設綁定 2、隱式綁定 先看兩段例子 下 ...


---恢復內容開始---

一、this是什麼東東?

  this是指包含它的函數作為方法被調用時所屬的對象。這句話理解起來跟卵一樣看不懂,但是如果你把它拆分開來變成這三句話後就好理解一點了。

  1.包含它的函數

  2.作為方法被調用時

  3.所屬的對象

二、this的綁定規則

  1、預設綁定  

var x = 0;
function num(){
    this.x = 1;
}
console.log(this.x);//0
num();
console.log(this.x);//1

//
當沒有使用let或者var時,聲明的變數是全局變數,指向window
//在這一形態下,其函數內部的this是與全局作用域時一樣,直接指向window,執行完num()後,更改了x的值,所以其形態 依然等價於window。
      function foo(){
      console.log(
this.a)     }     var a = 2;     foo(); //2     console.log(this.document === document); // true     // 在瀏覽器中,全局對象為 window 對象:     console.log(this === window); // true     this.a = 3;     console.log(window.a); // 3     this指向全局對象。在非嚴格模式中,當funcion被不帶任何修飾的函數直接引用進行調用的,只能使用預設綁定,無法應用其他規則  

 

    

  2、隱式綁定

    先看兩段例子   

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

var obj = {
    a:2,
    foo:foo
}

obj.foo() //2
//隱式綁定————調用位置使用obj上下文來引用函數,可以說函數被調用時obj對象“擁有”或者“包含”它,它就指向誰。
 

 

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

var obj2 = {
    a:42,
    foo:foo
}

var obj1 = {
   a:2,
   obj2:obj2,
   foo:foo }
obj1.foo() //2 obj1.obj2.foo()
//42 //此時可以控制台查看obj1,obj2對象里究竟包含了什麼
//當函數引用有上下文對象時,隱式綁定規則會把函數調用中的this綁定到這個上下文對象
//對象屬性引用鏈中只有最後一層在調用位置中起作用

下麵思考這一段會輸出什麼呢?

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

var obj = {
    a:2,
    foo:foo
}

var bar = obj.foo;  //這裡bar將引用foo函數本身,所以不帶有函數對象的上下文,this會直接指向window
bar() //?

//為什麼沒有隱式綁定?這種情況稱為隱式丟失。

//因為bar=obj.foo 而obj.foo指向foo 也就是bar = function foo(){console.log(this.a)}
foo中的this指向window,
//在window中並沒有對a進行定義,so,結果是undefined

接下來再看一段會是什麼結果呢?(參數傳遞時的隱式賦值)

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

function doback(fn){
    fn()
}

var obj = {
    a:2,
    foo:foo
}

var a = 'global';

doback(obj.foo) //?    顯然答案是global,但是為什麼呢?請繼續往下看!

//隱式丟失--被隱式綁定的函數會丟失綁定對象然後應用預設綁定。
//最後函數執行 doback(obj.foo)時,會進行參數傳遞,也就是 fn = obj.foo,就和上一個例子一樣了。既this指向的是window。


  

  3、顯示綁定

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

var obj = {
    a:2
}
foo.call(obj) //2

//顯式綁定--第一個參數是一個對象,接著在調用函數時將其綁定到this,通過foo.call(obj),我們可以在調用foo時強制把他的this綁定到obj上
function foo(){
    console.log(this.a)
}

var obj = {
    a:2
}

var a = '3333333';

var bar = function(){
    foo.call(obj)
}

bar() // 2
bar.call(window) //2

// 硬綁定後bar無論怎麼調用,都不會影響foo函數的this綁定
// 通過創建函數bar(),併在內部調用foo.call(obj),強制把foo的this綁定到obj上。硬綁定的bar之後無論如何調用函數,都只會在obj上調用foo。

我們來看一下他的應用:
function foo(num) {
    console.log( this.a, num);
    return this.a + num;
}

var obj = {
    a: 2
};

var bar = function() {
    return foo.call( obj, ...arguments ); // 將obj對象硬編碼進去
   //return foo.apply( obj, arguments ); // 也可以使用apply將obj對象硬編碼進去
};

var b = bar( 3 ); // 2 3
console.log( b ); // 5

 



function fn1(){
   console.log(1);
}
function fn2(){
    console.log(2);
}

fn1.call(fn2);     //輸出 1
 
fn1.call.call(fn2);  //輸出 2  這個暫時沒有搞懂,但是東鴿子大師中有講解,感興趣的小伙伴可以看看。

  

  4、new綁定

    我們不去深入瞭解構造函數,但要知道new來調用函數,或者說發生構造函數調用時,執行了哪些

    當代碼 new foo(...) 執行時:

 

    (1) 創建一個新對象,它繼承自foo.prototype.

    (2) 將構造函數的作用域賦給新對象(因此 this 就指向了這個新對象);new foo 等同於 new foo(),只能用在不傳遞任何參數的情況。

    (3) 執行構造函數中的代碼(為這個新對象添加屬性) ;

    (4) 返回新對象, 那麼這個對象會取代整個new出來的結果。如果構造函數沒有返回對象,那麼new出來的結果為步驟1創建的對象。

 

function foo(a){
    this.a = a;
}

var bar = new foo(2);  //創建一個新對象bar,它繼承了foo.prototype.  也就是bar這個對象有a這個屬性,且傳進去的是2,使用new來調用foo(..)時,會構造一個新對象,並把它綁定到foo(..)調用中的this上
console.log(bar.a) //2 

 

 

三、下麵做一個小練習看看你學會了嗎?

例一

function foo(a){ console.log(
this.a) } var obj1 = { a:2, foo:foo } var obj2 = { a:3, foo:foo } obj1.foo() //? obj2.foo() //? obj1.foo.call(obj2) //? obj2.foo.call(obj1) //?





答案:
obj1.foo() //2 隱式綁定
obj2.foo() //3 隱式綁定

obj1.foo.call(obj2) //3 顯式綁定
obj2.foo.call(obj1) //2 顯式綁定

通過答案得出:顯示綁定 > 隱式綁定
顯示綁定優先順序更高,所以在判斷時 應當 優先考慮 是否 存在 顯示綁定

 

 

 

例二

function foo(someting){
this.a = someting } var obj1 = { foo:foo } var obj2 = {}
obj1.foo(
2)
var bar = new obj1.foo(4)
console.log(obj1.a)
//? console.log(bar.a)//?







答案:
console.log(obj1.a) //2  
console.log(bar.a)  //4

通過答案得出: new綁定 > 隱式綁定
顯示綁定優先順序更高,所以在判斷時 應當 優先考慮 是否 存在 new綁定

 

 

需要註意的是:new和call/apply無法一起使用,因此無法通過new foo.call(obj)來直接測試

function foo(someting){
this.a = someting } var obj1 = {} var bar = foo.bind(obj1) //不知道bind()方法的同學可以直接點擊此處查看最騷的就是你同學貢獻的詳解。 bar(2) console.log(obj1.a)//? var baz = new bar(3) console.log(obj1.a)//? console.log(baz.a)//?






答案:2 2 3

通過答案得出:new綁定 > 顯示綁定
new修改了硬綁定調用bar(..)中的this,因為使用了new綁定,得到了一個名字為baz的新對象,並且baz.a的值為3.
所以 new綁定 > 顯示綁定 > 隱式綁定 > 預設綁定


 

 

 

 

在此特別鳴謝同事Jason大哥的share!!!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

---恢復內容結束---


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

-Advertisement-
Play Games
更多相關文章
  • 本文由雲+社區發表 作者:NaOH 概述 stetho是Facebook開源的一個Android調試工具,項目地址:facebook/stetho 通過Stetho,開發者可以使用chrome的inspect功能,對Android應用進行調試和查看。 功能概述 stetho提供的功能主要有: Net ...
  • 在MAC上使用APICloud同步代碼時出現錯誤,其實就是git位置的問題,簡單點就是把路徑映射下。 問題提示: Can't locate SVN/Core.pm in @INC (you may need to install the SVN::Core module) (@INC contain ...
  • OpenCV是一個基於BSD許可(開源)發行的跨平臺電腦視覺庫,可以運行在Linux、Windows、Android和Mac OS操作系統上。它輕量級而且高效——由一系列 C 函數和少量 C++ 類,同時提供了Python、Ruby、MATLAB等語言的介面,實現了和電腦視覺方面的很多通用演算法 ...
  • 前言 由於新申請的微信公眾號沒有留言功能了,沒有留言就無法跟讀者進行交互,寫出去的文章好像得不到反饋一樣,感覺有蠻難受的,所以就參考Ethanm的插件自己製作了一個小程式用於留言,來代替原版公眾號的留言功能。 當然你也可以選擇在A5上買一個可以留言的公眾號進行遷移,畢竟有些人註冊的比較早是有留言功能 ...
  • HTML5筆記 瞭解HTML5 新語義標簽 網頁佈局結構標簽及相容處理 多媒體標簽及屬性介紹 新表單元素及屬性 智能表單控制項 表單屬性 HTMl5中的API 獲取頁面元素及類名操作和自定義屬性 文件讀取 獲取網路狀態 獲取地理定位 本地存儲 操作多媒體 Canvas畫布 繪圖工具 繪圖方法 漸變方案 ...
  • CSS Grid 佈局是 CSS 中最強大的佈局系統。與 flexbox 的一維佈局系統不同,CSS Grid 佈局是一個二維佈局系統,也就意味著它可以同時處理列和行。通過將 CSS 規則應用於 父元素 (成為 Grid Container 網格容器)和其 子元素(成為 Grid Items 網格項 ...
  • NodeJS 第一天學習 嚴格模式 的嚴格模式是採用具有限制性JavaScript變體的一種方式,從而使代碼顯示地 脫離“馬虎模式/稀鬆模式/懶散模式“(sloppy)模式。 嚴格模式不僅僅是一個子集:它的產生是為了形成與正常代碼不同的語義。 嚴格模式對正常的 JavaScript語義做了一些更改 ...
  • 字元串轉json對象 方法一:var json = eval('(' + str + ')'); 方法二:return JSON.parse(str); json對象轉字元串 JSON.stringify(jsonobj); //可以將json對象轉換成字元串 例如: JSON字元串:var str ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...