this(執行上下文)

🚩 這個專欄是一個 JS 進階系列,當前內容為 JS 執行機制,建議按順序閱讀

執行上下文&作用域

詞法環境&變量環境

this(上下文對象) 🔹

概述

🌍 前提概要:

在上文 執行上下文&作用域 中,我們已經知道

  • 執行上下文的 thisValuethis 等價
  • 全局執行上下文的 this 指向全局對象

而函數執行上下文中的 thisValue 指向 ,我卻一筆帶過 ,現在打算放在這篇文章幫它整明白!

💡 我們每次調用函數時,解析器都會將一個 上下文對象 作為 隱含參數 傳遞進函數。 使用 this 來引用上下文對象,根據函數的 調用方式 不同,this 的值也不同。

函數中的 this

普通函數調用

在普通函數調用中,this 指向全局對象(非嚴格模式)或 undefined(嚴格模式)。

🌰舉個栗子

let a = {b: function () {let func = function () {console.log(this); //Window}func(); //普通函數調用},}
a.b(); //打印 Window

方法調用

當函數作為對象的方法調用時,this 指向調用該方法的對象。

🌰舉個栗子

const obj = {name: 'Alice',greet: function() {console.log(this.name);}
};obj.greet(); // 輸出: Alice

構造函數調用

當函數作為構造函數調用(使用 new 關鍵字)時,this 指向新創建的對象。

🌰舉個栗子

function Person(name) {this.name = name;
}const alice = new Person('Alice');
console.log(alice.name); // 輸出: Alice

箭頭函數中的 this

箭頭函數沒有自己的 this,它會捕獲其所在上下文的 this 值。這意味著箭頭函數中的 this 在定義時就已經確定,不會因為調用方式而改變。

🌰舉個栗子

const obj = {name: 'Alice',greet: function() {setTimeout(() => {console.log(this.name);}, 100);}
};obj.greet(); // 輸出: Alice

類中的 this

類本質上是基于構造函數原型繼承的語法糖 , 在類的方法中,this 指向類的實例。

🌰舉個栗子

class Person {constructor(name) {this.name = name;}greet() {console.log(this.name);}
}const alice = new Person('Alice');
alice.greet(); // 輸出: Alice

使用 callapplybind

call、apply、bind 方法:這三種方法可以明確指定 this 的值 , 即顯式設置this

call、apply、bind 原理

call

作用:

call 方法用于調用一個函數,并設置函數執行時的 this 值,同時可以傳遞參數列表。

語法:

func.call(thisArg, arg1, arg2, ...)

  • thisArg:函數執行時的 this 值。
  • arg1, arg2, ...:傳遞給函數的參數列表。

原理:

  1. 將函數的 this 綁定到 thisArg
  2. 立即執行函數,并傳入參數。

🌰舉個例子:

const person1 = {name: '張三',introduce: function (city, country) {console.log(`${this.name} is from ${city}, ${country}`);},
};
const person2 = {name: '李四',
};
person1.introduce.call(person2, '上海', '中國')

打印:李四 is from 上海, 中國

apply

作用:

apply 方法與 call 類似,用于調用一個函數并設置 this 值,但它的參數是以數組(或類數組對象)的形式傳遞的。

語法:

func.apply(thisArg, [argsArray])

  • thisArg:函數執行時的 this 值。
  • argsArray:傳遞給函數的參數數組。

原理:

apply 的原理與 call 幾乎相同,唯一的區別是參數傳遞方式。

🌰仍然是上面那個例子:

參數傳遞 必須是參數數組

person1.introduce.apply(person2, ['上海', '中國']);

bind

作用:

bind 方法用于創建一個新函數,并將原函數的 this 值綁定到指定的 thisArg。與 callapply 不同,bind 不會立即執行函數,而是返回一個綁定了 this 的新函數。

語法:

func.bind(thisArg, arg1, arg2, ...): newFunc

  • thisArg:新函數執行時的 this 值。
  • arg1, arg2, ...:預先傳遞給新函數的參數(可選)。
  • return newFunc: 返回一個綁定了 this 的新函數。

原理:

bind 的原理可以理解為:

  1. 返回一個新函數。
    • bind 不會改變原函數,而是返回一個新的函數。
  2. 新函數執行時,this 被綁定到 thisArg
    • 新函數的 this 值會被固定為傳入的 第一個參數。例如 f.bind(obj) ,實際上可以理解為 obj.f(),這時,f 函數體內的 this 自然指向的是 obj
  3. 可以預先傳遞部分參數(柯里化)。
    • 可以在調用新函數時,傳入額外的參數,這些參數會在調用時被傳遞給原函數。
預設參數
案例1:
function multiply(a, b) {return a * b;
}
const double = multiply.bind(null, 2); // 固定第一個參數為2
console.log(double(5)); // 輸出: 10

在這個例子中:

  • null 是固定的 this 值,因為我們不需要設置 this
  • 2 是預設的第一個參數(對應原函數的 a),而在調用 double(5) 時,5 會作為第二個參數(對應原函數的 b)傳遞。
  • double 函數實際上是 multiply 函數的一個“封裝”,它將第一個參數固定為 2,而 this 的值被設置為 null,這在這里并不重要,因為 multiply 函數并沒有使用 this
案例 2
function f(y, z){return this.x + y + z;
}
let m = f.bind({x : 1}, 2);
console.log(m(3));
//6

在這個例子中:

  1. 參數{x : 1}
    • 這里bind方法會把它的第一個實參綁定給f函數體內的 this,所以這里的 this即指向{x : 1}對象
  2. **參數 **2
    • 從第二個參數起,會依次傳遞給原始函數,這里的第二個參數 2,即是 f 函數的 y參數,
  3. **參數 **3
    • 最后調用 m(3)的時候,這里的 3 便是最后一個參數 z 了,所以執行結果為 1 + 2 + 3 = 6

分步處理參數的過程其實是一個典型的 函數柯里化 的過程(Curry)

案例

分析代碼:

let a = {b: function () {let func = function () {console.log(this.c);//undefined}func(); //普通函數調用},c : 'Hello!'}
a.b(); // undefined

undefined的 原因:

😃func 函數是在 a.b() 方法內定義的,調用時是作為一個普通函數調用,而不是作為對象的方法調用。這導致 this 的指向變成了全局對象(在瀏覽器中是 window),而不是對象 a

🤔在學習完所有this指向的場景后,你能想出不同的方法去使得this.c能正常訪問嗎?

解決方法

賦值

可以通過賦值的方式將 this 賦值給 that

let a = {b: function () {let self = this //將 this 賦值給 thatlet func = function () {console.log(self.c);//修改成self}func();},c: 'Hello!'}
a.b(); //輸出: Hello!
使用箭頭函數
let a = {b: function () {let func = () => {console.log(this.c);}func();},c: 'Hello!'
}
a.b(); // 輸出: Hello!
使用call / apply
let a = {b: function () {let func = function () {console.log(this.c);}func.call(this); //call},c: 'Hello!'
}
a.b(); // 輸出: Hello!
使用 bind方法
//寫法一
let a = {b: function() {let func = function() {console.log(this.c);}.bind(this); //返回新函數 覆蓋 func();},c: 'Hello!'
}
a.b(); // 輸出: Hello!//寫法二
let a = {b : function(){let func = function(){console.log(this.c);}func.bind(this)(); //立即執行},c : 'Hello!'
}a.b(); // 輸出: Hello!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/news/899197.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/899197.shtml
英文地址,請注明出處:http://en.pswp.cn/news/899197.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

計算機網絡——數據鏈路層的功能

目錄 物理鏈路 邏輯鏈路 封裝成幀(組幀) 幀定界 透明傳輸 SDU 差錯控制 可靠傳輸 流量控制 介質訪問控制 主機需要實現第一層到第五層的功能,而路由器這種節點只需要實現第一層到第三層的這些功能 假設左邊用戶需要給右邊用戶發送…

計算機網絡 --應用層

計算機網絡 --應用層 一、應用層概述 1. 功能 應用層為應用程序通信提供直接服務,這種服務是用戶能夠直接感知到的數據通信服務。核心功能包括: 文件傳輸:實現不同設備間文件的傳輸操作。訪問管理:對用戶訪問資源等進行管理。電…

企業級Linux服務器初始化優化全流程

實戰指南:企業級Linux服務器初始化優化全流程 本文基于某電商平臺百萬級并發服務器的真實調優案例整理,所有操作均在Rocky Linux8.5驗證通過,不同發行版請注意命令差異 一、服務器安全加固(Situation-Task-Action-Result&#xff…

OpenAI流式解析

OpenAI 流式的代碼: 首選一般請使用os.getenv 去讀環境變量的內容 注意使用pip install python-dotenv 的安裝方法 load_dotenv 是這個庫提供的一個函數,用于讀取 .env 文件并將其中定義的鍵值對設置為系統的環境變量。 默認情況下,load_…

數據抓取的緩存策略:減少重復請求與資源消耗

在數據采集領域,爬蟲效率是決定項目成敗的關鍵因素之一。傳統的爬蟲架構往往因請求頻繁、資源消耗較大以及重復抓取等問題,導致效率低下。這些問題不僅拖慢了數據獲取的速度,還可能引發目標服務器的過載風險,甚至導致爬蟲被限制。…

k8s部署argocd

前言 ArgoCD是一個基于Kubernetes的GitOps持續交付工具,應用的部署和更新都可以在Git倉庫上同步實現,并自帶一個可視化界面。本文介紹如何使用GitHelmArgocd方式來實現在k8s中部署和更新應用服務; 安裝Argocd 準備一個k8s集群,然…

【Linux】MAC幀

目錄 一、MAC幀 (一)IP地址和MAC地址 (二)MAC幀格式 (三)MTU對IP協議的影響、 (四)MTU對UDP協議的影響 (五)MTU對TCP協議的影響 二、以太網協議 &…

MySQL - 數據庫基礎操作

SQL語句 結構化查詢語言(Structured Query Language),在關系型數據庫上執行數據操作、數據檢索以及數據維護的標準語言。 分類 DDL 數據定義語言(Data Definition Language),定義對數據庫對象(庫、表、列、索引)的操作。 DML 數據操作語言(Data Manip…

GraalVM原生鏡像支持:Spring Cloud應用啟動速度提升90%

引言:當Spring Cloud遇見GraalVM,啟動時間進入秒級時代 傳統Spring Cloud應用因動態類加載、反射等機制導致啟動緩慢(通常超過30秒),在Serverless和Kubernetes滾動更新場景下成為性能瓶頸。Spring Cloud 2023.x通過**G…

【Unity3D】攝像機適配場景以及Canvas適配

目錄 寬度不變策略 高度不變策略 寬度不變策略 開發分辨率 750*1334 (寬高比:0.56) 真機分辨率 1170*2532 (寬高比:0.46) 真機寬高比<開發寬高比&#xff0c;采用寬度不變策略 理由&#xff1a;小于代表真機高度比開發高度更大&#xff0c;因此不需要擔心高度上…

HarmonyOS:基于axios實現文件的下載以及下載進度的監聽

#前言&#xff1a;項目開發中&#xff0c;避免不了實現文件下載功能&#xff0c;其他平臺的下載都很成熟&#xff0c;網上的例子也比較多&#xff0c;我就自己項目中實現的下載功能做個總結&#xff0c;你可以參考我的寫法實現功能。 下載封裝基于axios實現的下載功能。 1.下載…

簡單一周日期展示及選擇切換

醫院掛號&#xff0c;可能需要切換日期&#xff0c;選擇一周內的某一天。 提供一周內的日期段&#xff0c;通過點擊&#xff0c;切換到不同天。 簡單的js&#xff0c;html實例。切換玩調用后臺接口&#xff0c;實現后續邏輯。 使用Vue,插值語法&#xff0c;更簡單。 一周日歷…

二叉樹的前,中,后序遍歷

我們來了解一下二叉樹的遍歷&#xff0c;話不多說 二叉樹的遍歷的概念&#xff1a; 二叉樹有四種遍歷方式&#xff0c;分別為前序遍歷&#xff0c;中序遍歷&#xff0c;后序遍歷和層序遍歷&#xff0c;但我們今天談談前三種&#xff0c;并實現它 前序遍歷&#xff1a; 按照根…

golang Error的一些坑

golang Error的一些坑 golang error的設計可能是被人吐槽最多的golang設計了。 最經典的err!nil只影響代碼風格設計&#xff0c;而有一些坑會導致我們的程序發生一些與我們預期不符的問題&#xff0c;開發過程中需要注意。 ?? errors.Is?判斷error是否Wrap不符合預期 ?…

逼用戶升級Win11,微軟開始給Win10限速

隨著Windows10的支持時間越來越短&#xff0c;微軟也加大了對Win10用戶的驅趕力度。 最近&#xff0c;微軟官宣了將要在今年6月份降低OneNote for Windows 10的同步速度。軟件也將和Windows10在今年的10月14日一同停止支持和維護。 這將影響實時協作和多設備訪問。 對OneNote…

SpringMVC_day02

一、SSM 整合 核心步驟 依賴管理 包含 SpringMVC、Spring JDBC、MyBatis、Druid 數據源、Jackson 等依賴。注意點&#xff1a;確保版本兼容性&#xff08;如 Spring 5.x 與 MyBatis 3.5.x&#xff09;。 配置類 SpringConfig&#xff1a;掃描 Service 層、啟用事務管理、導入…

Android14 原生PackageInstaller安裝某些apk報錯問題

最近遇到Android14安裝客戶一個大型app的時候&#xff0c;執行到開始安裝的時候就直接閃退了&#xff0c;查看log發現下面報錯&#xff1a; 03-25 18:01:29.531 3085 3085 E AndroidRuntime: java.lang.RuntimeException: Could not copy bitmap to parcel blob. 03-25 18:01:2…

SQLAlchemy關鍵詞搜索技術深度解析:從基礎過濾到全文檢索

在數據驅動的應用開發中&#xff0c;基于關鍵詞的模糊查詢是常見的業務需求。SQLAlchemy作為Python生態中最流行的ORM框架&#xff0c;提供了多種實現關鍵詞搜索的技術方案。本文將從性能、適用場景和技術復雜度三個維度&#xff0c;系統對比分析SQLAlchemy中關鍵詞搜索的最佳實…

基于 ffmpeg 實現合并視頻

ffmpeg是一個強大的多媒體處理工具&#xff0c;支持視頻文件的合并。 列出目錄下所有MP4文件 import os import glob# 當前目錄 directory os.getcwd() directory "/directory/to/mp4/*"# 列出目錄下所有MP4文件 files glob.glob(directory)# 排序 files.sort(…

算法每日一練 (20)

&#x1f4a2;歡迎來到張翊塵的技術站 &#x1f4a5;技術如江河&#xff0c;匯聚眾志成。代碼似星辰&#xff0c;照亮行征程。開源精神長&#xff0c;傳承永不忘。攜手共前行&#xff0c;未來更輝煌&#x1f4a5; 文章目錄 算法每日一練 (20)不同路徑 II題目描述解題思路解題代…