JavaScript this用法總結

来源:http://www.cnblogs.com/xfshen/archive/2016/10/30/6011541.html
-Advertisement-
Play Games

在JavaScript中,this關鍵字可以說是最複雜的機制之一。對this的作用機制缺乏比較深入的理解很容易在實際開發中出現問題。 1、this的作用 為什麼要在JavaScript中使用this呢?因為this提供了一種簡明的方式來隱式傳遞一個對象引用,可以讓函數介面設計的簡單且容易復用: 通過 ...


在JavaScript中,this關鍵字可以說是最複雜的機制之一。對this的作用機制缺乏比較深入的理解很容易在實際開發中出現問題。

1、this的作用

為什麼要在JavaScript中使用this呢?因為this提供了一種簡明的方式來隱式傳遞一個對象引用,可以讓函數介面設計的簡單且容易復用:

function display() {
    console.log(this.name);
}

var obj1 = {name: "obj1"};
var obj2 = {name: "obj2"};

display.call(obj1);  //  "obj1"
display.call(obj2);  //  "obj2"

 通過call方法,我們可以在調用display函數時為this傳入不同的對象。如果不使用this關鍵字,那麼上面的函數就需要顯示增加一個調用時上下文參數:

function display(context) {
    console.log(context.name);
}

var obj1 = {name: "obj1"};
var obj2 = {name: "obj2"};

display(obj1);  //  "obj1"
display(obj2);  //  "obj2"

實際上這不夠簡潔,當使用模式比較複雜時,顯示的上下文傳遞會讓代碼變得混亂複雜。使用this關鍵字,我們可以在調用時為this傳入不同的對象引用,保證了方法的使用靈活性。

 

2、this的使用複雜性

this使用機制複雜,在開發容易出問題的根本原因在於:this是在運行時綁定,而不是在編寫時綁定,this實際值取決於函數調用時的上下文。this的綁定和函數聲明的位置沒有關係,只取決於函數的調用方式。在JavaScript中,當函數被調用時,會創建一個活動記錄(執行時上下文),這個記錄包含函數在何處調用、函數的調用方法和傳入參數等信息,this會記錄其中一個屬性。判斷this實際綁定值,關鍵在於分析函數實際調用的位置。

 

3、this綁定規則

前面說了函數的實際調用位置決定了this的綁定值。在JavaScript中,this有4種綁定規則。

3.1、new綁定

在JavaScript中使用new調用函數會自動執行下麵的操作:

  (1)創建一個新的對象

  (2)對新對象執行原型鏈接

  (3)新對象會被綁定到函數的this

  (4)如果函數沒有返回其他對象,那麼新對象會被返回

 

new綁定容易理解,下麵是一段常見的用new調用函數創建對象的代碼:

function Book(name, author, isbn) {
    this.name = name;
    this.author = author;
    this.isbn = isbn;
}

let book = new Book("Zakas", "ES6", 12345);

console.log(book.name);  //  "Zakas"

 3.2、隱式綁定

 當對象內部包含一個指向函數的屬性,並且在調用時通過這個屬性間接引用函數(obj.prop()的形式),那麼函數內的this會隱式指向這個對象,也即隱式綁定:

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

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

obj.foo();  //  2

在調用位置上,函數是通過obj.foo來引用的,可以說函數被調用時obj對象擁有或包含它。此時,this綁定在obj這個上下文對象上。

3.3、顯示綁定

在某些情況下,我們希望函數內的this綁定在某些指定的對象上,這稱為顯示綁定。在JavaScript中可以使用call和apply為函數顯示指定this綁定。call和apply的第一個參數是一個對象,這個對象會被綁定到this上:

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

var obj = {
  a:2
};

foo.call(obj);  //  2

使用bind也可以讓this綁定在指定對象上,bind綁定也是一種顯示綁定,又稱為硬綁定:

function foo(something) {
    this.a = something;
}
var obj1 = {};
var bar = foo.bind(obj1);

bar(2);
console.log(obj1.a);  //  2

3.4、預設綁定

當使用獨立函數調用(func()形式),會發生預設綁定,可以把這條規則看成是無法使用其他規則時的預設規則。看下麵的示例代碼:

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

var a = 2;

foo();  //  2

當調用foo時,使用預設綁定規則,this被綁定到全局對象上。在strict模式下,this會綁定到undefined。

 

4、綁定優先順序

上面4種綁定規則獨立使用的話,判斷this的綁定值並不複雜。但實際函數調用時,可能多條綁定規則都可以使用,那麼這時就要根據每個規則的綁定優先順序來判斷this實際的綁定值。接下來看各種綁定規則的優先順序。

4.1、預設綁定優先順序最低

預設綁定的優先順序最低,這個容易理解。因為當無法使用其他的綁定規則時才會使用預設規則。

4.2、顯示綁定優先順序高於隱式綁定

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

var obj1 = {a: 2, foo: foo};
var obj2 = {a: 3, foo: foo};

obj1.foo();  //  2
obj1.foo.call(obj2);  //  3

上面的代碼中,obj1.foo()使用隱式綁定規則,this綁定到obj1對象上。obj1.foo.call()可同時使用隱式綁定和顯示綁定規則,顯示綁定優先順序高於隱式綁定,this綁定到obj2對象上。

4.3、new綁定優先順序高於隱式綁定

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

var obj1 = {
    foo: foo
};

var obj2 = {};

obj1.foo(2);
console.log(obj1.a);  //  2

obj1.foo.call(obj2, 3);
console.log(obj2.a);  //  3

var bar = new obj1.foo(4);
console.log(obj1.a);  //  2
console.log(bar.a);  //  4

上面代碼中,new obj1.foo(4)可同時使用new綁定和隱式綁定。由bar.a的值為4可以知道,new綁定優先順序高於隱式綁定。

4.4、new綁定優先順序高於顯示綁定

function foo(something) {
    this.a = something;
}
var obj1 = {};
var bar = foo.bind(obj1);

bar(2);
console.log(obj1.a);  //  2

var baz = new bar(3);
console.log(obj1.a);  //  2
console.log(baz.a);  //  3

上面代碼中,new bar(3)可同時使用new綁定和bind綁定。baz.a的值為3,說明new綁定優先順序高於隱式綁定。

4.5、綜述

現在可以根據this綁定優先順序判斷函數在調用位置實際綁定的值。實際可以按照下麵的順序判斷:

  (1、函數是否在new中調用?如果是的話this綁定新創建的對象。調用例子:var bar = new foo()。

  (2、函數是否通過apply、call顯示綁定或者bind硬綁定?如果是,this綁定指定的對象。調用例子:var bar = foo.call(obj)。

  (3、函數是否在某個上下文對象中調用(隱式綁定)?如果是,this綁定在上下文對象上。調用例子:var bar = obj.foo()。

  (4、如果都不是的話,使用預設綁定。在嚴格模式下,this綁定到undefined,在非嚴格模式下,綁定到全局對象。調用例子:var bar = foo()。

 

5、箭頭函數中的this

ES6中引入了箭頭函數,箭頭函數使用操作符=>定義。箭頭函數不使用上面4種this綁定規則,而是根據外層作用域來決定this:

function foo() {
    return (a) => {
        console.log(this.a);
    };
}    

var obj1 = {a:2};
var obj2 = {a:3};

var bar = foo.call(obj1);
bar.call(obj2);  //  2

foo內部的箭頭函數創建時,foo函數內this綁定到obj1上,bar(箭頭函數)的this也會綁定到obj1上,箭頭函數內的this是不能被修改的。


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

-Advertisement-
Play Games
更多相關文章
  • Spring經過大神們的構思、編碼,日積月累而來,所以,對其代碼的理解也不是一朝一夕就能快速完成的。源碼學習是枯燥的,需要堅持!堅持!堅持!當然也需要技巧,第一遍學習的時候,不用關註全部細節,不重要的代碼可以先忽略掉,達到理解大體的架子及流程,避免第一次就陷入某個坑裡出不來。第二遍針對某個流程更深入 ...
  • 這是一個計數鎖,說白了,就是當你上鎖的時候,只有計數減少到0的時候,才會釋放鎖 結果 ...
  • 接入層session設計原則: 1、Session—讀寫請求使用的上下文對象,稱之會話。 業務總有狀態的:用戶下單購買、登錄狀態、好友狀態、消息發送情況等; 這些有狀態的信息隨用戶操作變化。 單機環境下: 集群設計: --session複製: 所有接入層伺服器之間同步session數據; 每台接入服 ...
  • 作為一個初級開發者,可能不會接觸到代理模式,但是在很多框架的使用中都不知不覺使用了代理模式,比如servlet的過濾器鏈,spring的AOP,以及spring mvc的攔截器等。所以瞭解代理模式對於個人的成長是不可避免的。 在某些情況下,一個客戶不想或者不能直接引用一個對象,此時可以通過一個稱之為 ...
  • 一直認為原型鏈太過複雜,尤其看過某圖後被繞暈了一整子,今天清理硬碟空間(渣電腦),偶然又看到這圖,勾起了點回憶,於是索性複習一下原型鏈相關的內容,表達能力欠缺邏輯混亂別見怪(為了防止新人__(此處指我)__被在此繞暈,圖片就放在末尾了。) 以下三點需要謹記 1.每個對象都具有一個名為__proto_ ...
  • 在JavaScript中一共有4種調用模式: 函數調用模式 方法調用模式 構造器調用模式 間接調用模式,通過call()和apply()進行 1. 函數調用模式 普通函數調用模式,如: 在一個調用中, (1)每個參數表達式計算的結果作為實參傳遞給聲明函數時定義的形參; (2)this被綁定到全局變數 ...
  • 一、Float的特性 1. 應用於文字圍繞圖片 2. 創建一個塊級框 3. 多列浮動佈局 4. 浮動元素的寬度、高度自適應,但可以設置其值。 二、核心解決的問題 文字圍繞圖片:img標簽與多個文本標簽放置在一個容器中,如果img浮動,文本標簽會圍繞圖片。 2.1 這是一個問題 浮動元素與正常元素相鄰 ...
  • 正則表達式 var str='test' var reg=/^test$/ var result=reg.test (str) // 需要檢測的目標 console.log(result) //ture var str='test' var reg=/^test$/ var result=reg.t ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...