前端js中this指向及改變this指向的方法

来源:https://www.cnblogs.com/hjson/archive/2019/01/11/10254555.html
-Advertisement-
Play Games

js中this指向是一個難點,花了很長時間來整理和學習相關的知識點。 一、 this this是JS中的關鍵字, 它始終指向了一個對象, this是一個指針; 參考博文: 1. "JavaScript函數中的this四種綁定形式" 2. "this指向及改變this指向的方法" 二、 this顯示綁 ...


js中this指向是一個難點,花了很長時間來整理和學習相關的知識點。

一、 this

this是JS中的關鍵字, 它始終指向了一個對象, this是一個指針;

參考博文:

  1. JavaScript函數中的this四種綁定形式
  2. this指向及改變this指向的方法

二、 this顯示綁定和隱式綁定

1. this顯示綁定

 含義: 當一個函數沒有明確的調用對象的時候, 也就是單純作為獨立函數調用的時候, 將對函數的this使用預設綁定: 綁定到全局的window對象

 在顯式綁定下: 函數將取得在“ 包含對象“ 里的永久居住權, 一直都會” 住在這裡“
在這裡插入圖片描述

1.1 全局函數

function fire() {
    console.log(this === window); //fire此時是全局的方法,this指向window
}
fire(); // 輸出true

1.2 函數內嵌套函數

function fire() {
    // 我是被定義在函數內部的函數哦!
    function innerFire() {
        console.log(this === window); //未明確調用對象,this指向window
    }
    innerFire(); // 獨立函數調用
}
fire(); // 輸出true
innerFire();

示例:

var a = 1;
console.log(this.a); //1 因為此時this指向了window,因而調用1
function fire() {
    var a = 2;
    console.log(this.a); //1 因為此時this指向了window,因而調用1

    function innerFire() {
        var a = 3;
        console.log(this.a); //1 因為此時this指向了window,因而調用1
    }
    innerFire();
}
fire(); //輸出1

 與作用域的區別: 全局作用域和局部作用域, 去掉this可發現區別

var a = 1;
console.log(a); //1 a在全局作用域
function fire() {
    var a = 2;
    console.log(a); // 2 fire函數作用域
    function innerFire() {
        var a = 3;
        console.log(a); //3 此時列印輸出a,a在innerFIre作用域。從自身作用域查找變數,未找到才網上查找
    }
    innerFire();
}
fire();

1.3 對象內層函數內部函數

var obj = {
    fire: function () { //此時的fire函數其實用到了隱式綁定
        function innerFire() {
            console.log(this === window); //未明確調用對象,this指向window
        }
        innerFire();
    }
}
obj.fire(); //輸出 true

示例:

var a = 1;
console.log(this.a); //1 this指向全局變數window
var obj = {
    a: 2,
    fire: function () {
        var a = 3;
        console.log(this.a); //2 因為是obj.fire(),調用了fire函數,因為this指向了obj,輸出了obj下的a=2
        function innerFire() {
            var a = 4;
            console.log(this.a); //1 未明確調用對象,this指向window
        }
        innerFire(); //沒有明確調用的對象
        console.log(this.a); //2 this指向obj
    }
}
obj.fire();

2、 this隱式綁定

a.隱式綁定

 當函數被一個對象“ 包含” 的時候, 我們稱函數的this被隱式綁定到這個對象裡面, 這時候, 通過this可以直接訪問所綁定的對象裡面的其他屬性, 比如下麵的a屬性

 在隱式綁定下: 函數和只是暫時住在“ 包含對象“ 的旅館裡面, 可能過幾天就又到另一家旅館住了
在這裡插入圖片描述

var obj = {
    a: 1,
    fire: function () { //此時函數的this被隱式綁定到了對象obj
        console.log(this == obj); // obj中有fire函數,因而預設this指向obj
        console.log(this.a); // 1 this.a 相當於obj.a =1
    }
}
obj.fire(); // 輸出1 

 相同的方法:
 fire函數並不會因為它被定義在obj對象的內部和外部而有任何區別,

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

var obj = {
    a: 1,
    fire: fire
}
obj.fire(); // 輸出1

b.動態綁定:
 this實在代碼運行期綁定而不是在書寫期

var obj = {
    a: 1, // a是定義在對象obj中的屬性 1
    fire: function () {
        console.log(this.a)
    }
}
var a = 2; // a是定義在全局環境中的變數 2
obj.fire(); //1  此時fire的指向時obj
var fireInGrobal = obj.fire; //因為fireInGrobal是全局變數,this對於obj的綁定丟失,綁定到了全局window
fireInGrobal(); // 輸出 2 輸出全局變數啊
var a = 2;
var obj = {
    a: 1, // a是定義在對象obj中的屬性
    fire: function () {
        console.log(this.a)
    }
}

function otherFire(fn) { //全局函數,this綁定window
    fn();
}
otherFire(obj.fire); // 輸出2   this對於obj的綁定丟失,綁定到了全局this上面
var obj = {
    a: 1,
    obj2: {
        a: 2,
        obj3: {
            a: 3,
            getA: function () { //obj3.getA()   this綁定到了obj3當中
                console.log(this.a)
            }
        }
    }
}
obj.obj2.obj3.getA(); // 輸出3

三、 this指向

 this的指向不是由定義this決定的, 而是隨腳本解析自動賦值的。

1. 全局環境作用域: this在全局環境始終指向window


 變數形式

console.log(this === window) // true
console.log(window.alert === this.alert) // true
console.log(this.parseInt("021", 10)) // 21
var fruit = "banana"; // 定義一個全局變數,等同於window.fruit = "banana"

2. 函數環境 作用域: 函數由誰調用, this就指向誰

2.1 非嚴格模式

function fn() {
    console.log(this); //window
}
fn() === window; // true;window.fn(),此處預設省略window

2.2 嚴格模式

  a 全局環境下, this指向window

"use strict";
this.b = "MDN";
console.log(this == window) // "MDN"
console.log(b) // "MDN"

  b 函數環境下, this為undefined

function fn() {
    "use strict"; // 這裡是嚴格模式
    console.log(this); //window
}
fn() === undefined //true

3 對象中的方法函數調用: 指向 該方法所屬的對象
 隱式調用

var obj = {
    a: 1,
    fn: function () {
        return this;
    }
}
console.log(obj.fn() == obj); //true  函數被obj調用,指向obj

 this動態綁定

var obj = {
    a: 1,
    fn: function () {
        return this;
    }
}
console.log(obj.fn()); //1  函數被obj調用,指向obj,輸出obj的a=1
var a = 2;
var newfun = obj.fn; //此時更改this指向為全局變數newfun
newfun(); //2 ,this訪問全局變數a=2

4 在構造函數中: this始終指向新對象
在這裡插入圖片描述

function Person(age, name) {
    this.age = age;
    this.name = name
    console.log(this) // 此處 this 分別指向 Person 的實例對象 p1 p2
}
var p1 = new Person(18, 'zs')
var p2 = new Person(18, 'ww')

在這裡插入圖片描述
5 通過事件綁定的方法: this 指向 綁定事件的對象

oBtn.onclick = function () {
        console.log(this); // btn
    }

    <
    button id = "btn" > hh < /button>

6 定時器函數: 因為是非同步操作, this 指向 window

 延時函數內部的回調函數的this指向全局對象window( 當然我們可以通過bind方法改變其內部函數的this指向)

 我們常見的window屬性和方法有alter, document, parseInt, setTimeout, setInterval, location等等, 這些在預設的情況下是省略了window首碼的。( window.alter = alter)。

6.1 普通定時器

setInterval(function () {
    console.log(this); // window
}, 1000);

在這裡插入圖片描述
6.2 定時器嵌套

function Person() {
    this.age = 0;
    setTimeout(function () {
        console.log(this);
    }, 3000);
}

var p = new Person(); //3秒後返回 window 對象

6.3 可以改變this指向 - 想見三方法

function Person() {
    this.age = 0;
    setTimeout((function () {
        console.log(this);
    }).bind(this), 3000);
}
var p = new Person(); //3秒後返回構造函數新生成的對象 Person{...}

7 自執行函數(匿名函數): 指向全局變數window

(function inner() {
    console.log(this); //this ==> window
})();

8 箭頭函數

要點:

a. 箭頭函數的this是在定義函數時綁定的, 不是在執行過程中綁定的
b. 箭頭函數中的this始終指向父級對象
c. 所有 call() / apply() / bind() 方法對於箭頭函數來說只是傳入參數, 對它的 this 毫無影響。
var obj = {
    a: 1,
    fn: () => {
        //箭頭函數中的this始終指向定義時的環境
        //箭頭函數中的this始終指向父級對象
        console.log(this); //對象內的this調用時一般指向obj,而箭頭函數在創建時就指向了obj的父級對象window
    }
}
obj.fn(); //window

四、 更改this指向

 每個Function構造函數的原型prototype, 都有方法
call(), apply(), bind()

總結:
a call(), apply()
在特定作用域調用函數
b bind()
會創建一個函數的實例, this會被綁定到bind() 函數
bing() 綁定this, bind()() 調用函數

1. call() 方法

var Person = {
    name: "zhangsan",
    age: 19
}

function aa(x, y) {
    console.log(x + "," + y);
    console.log(this);
    console.log(this.name);

}

aa(4, 5); //this指向window--4,5  window  空

aa.call(Person, 4, 5); //this指向Person--4,5  Person{}對象  zhangsan

在這裡插入圖片描述
2. apply() 方法

 apply() 與call() 非常相似, 不同之處在於提供參數的方式, apply() 使用參數數組, 而不是參數列表

var Person = {
    name: "zhangsan",
    age: 19
}

function aa(x, y) {
    console.log(x + "," + y);
    console.log(this);
    console.log(this.name);

}

aa.apply(Person, [4, 5]); //this指向Person--4,5  Person{}對象  zhangsan

在這裡插入圖片描述

3. bind() 方法
 bind() 創建的是一個新的函數( 稱為綁定函數), 與被調用函數有相同的函數體, 當目標函數被調用時this的值綁定到 bind() 的第一個參數上
在這裡插入圖片描述

var Person = {
    name: "zhangsan",
    age: 19
}

function aa(x, y) {
    console.log(x + "," + y);
    console.log(this);
    console.log(this.name);

}

aa.bind(Person, 4, 5); //只是更改了this指向,沒有輸出
aa.bind(Person, 4, 5)(); //this指向Person--4,5  Person{}對象  zhangsan

在這裡插入圖片描述
4. 存儲this指向到變數中

var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
    var _this = this; //將this儲存在變數中,而且不改變定時器的指向
    setTimeout(function () {
        console.log(_this); //註意這裡是_this,而不是this-- <div id="div1">點擊</div>
        console.log(this); //定時器的指向沒有被改變--仍然是window
    }, 1000)
}

在這裡插入圖片描述

在這裡插入圖片描述

五、 改變this指向綜合案例**

1、 為更改this指向

var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
        setTimeout(function () {
            console.log(this); //點擊時輸出 window對象
        }, 1000)
    }

    <
    div id = "div1" > 點擊 < /div>

在這裡插入圖片描述
2、 更改this指向 - bing, call, apply
 在定時器外, 在綁定事件中的this肯定指向綁定事件的對象div啊, 用call和apply都行

var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
    setTimeout(function () {
        console.log(this); // 更改this指向為 <div id="div1">點擊</div>
    }.bind(this), 1000)
}

在這裡插入圖片描述
3、 存儲this指向到變數中

var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
    var _this = this; //將this儲存在變數中,而且不改變定時器的指向
    setTimeout(function () {
        console.log(_this); //註意這裡是_this,而不是this-- <div id="div1">點擊</div>
        console.log(this); //定時器的指向沒有被改變--仍然是window
    }, 1000)
}

在這裡插入圖片描述
在這裡插入圖片描述


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

-Advertisement-
Play Games
更多相關文章
  • 有時候在我們在新增數據時,需要自動生成主鍵id等,就經常會遇到需要生成隨機數的方法。 下麵先介紹一種比較簡單的生成隨機數方法: 接著我們在我們需要的函數中去調用這個產生隨機數的方法: (下麵的案例是我自己寫的項目中用到的,下麵的第12行就調用了上面寫的生成隨機數函數的方法RndNum,並設置了6位隨 ...
  • 獲取功能變數名稱(第一種方法): 獲取功能變數名稱(第二種方法): 獲取埠號: 獲取主機+埠號: 需要註意的是獲取的功能變數名稱不包括“http://”。 在此我寫了一個方法用於根據本地環境和線上環境獲取功能變數名稱的方法: ...
  • 今天又是忙碌的一天,但是想到明天就雙休日了心情頓時開朗了,哈哈~ 廢話不多說,相信很多小伙伴都在項目中會用到側邊懸浮導航吧? 就是在網站首頁或者所有頁面的邊上懸浮這一條快捷入口或者工具吧? 是不是因為每次都要去寫這個功能而感到無聊呢? 今天我就來安利一波我的自定義側邊欄工具吧!! 例如樓下這幾個就很 ...
  • 轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。原文出處:https://wanago.io/2018/07/23/webpack-4-course-part-three-working-with-plugins/ 大家好!今天我們介紹插件這個概念。插件與l ...
  • 1.JavaScript 語句 JavaScript 語句是發給瀏覽器的命令。 這些命令的作用是告訴瀏覽器要做的事情。 2.分號 ; 分號用於分隔 JavaScript 語句。 通常我們在每條可執行的語句結尾添加分號。 使用分號的另一用處是在一行中編寫多條語句。 案例: 3.JavaScript 代 ...
  • 書接上文,我們繼續開發。 1.界面設計 首先我先用PS設計出如圖1的播放器界面。詳細設計步驟不再表述,這是美工的主要工作,下麵我主要講解一下切圖工作,這部分工作我認為還是自己動手比較合適,美工不知道我們的需求,也不知道怎麼切割符合我們的要求,所以要親自動手。掌握一些圖片設計工具還是十分有必要的 我們 ...
  • 1.JavaScript 語法 JavaScript 是一個腳本語言。 它是一個輕量級,但功能強大的編程語言 2.JavaScript 字面量 在編程語言中,一般固定值稱為字面量,如 3.14。 數字(Number)字面量 可以是整數或者是小數,或者是科學計數(e); 字元串(String)字面量 ...
  • 註:本人小白一個,目前還在校學習,這次老師讓做的項目需要用到這個功能,所以花了一些時間搞了一下,本次案列實現功能為 用戶註冊信息,如果資料庫對應表中存在部分信息,點擊已有的用戶的用戶名,自動補全其它已有的基本信息 實現思路:通過AutoComplete提示,非同步通過用戶名查詢全表,充當AutoCom ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...