最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript?this綁定規(guī)則:告別踩坑指南

 更新時(shí)間:2026年05月23日 09:02:42   作者:林恒  
本文通過具體代碼實(shí)例,詳細(xì)講述了JavaScript中this的綁定規(guī)則,分析了this的5種綁定規(guī)則以及箭頭函數(shù)中的this的特殊行為,總結(jié)判斷this指向的口訣,感興趣的朋友一起看看吧

前言

在JavaScript學(xué)習(xí)中,this絕對(duì)是“讓人又愛又恨”的存在——它看似簡(jiǎn)單,用起來卻總讓人摸不著頭腦,一不小心就踩坑。有人說它是“動(dòng)態(tài)代詞”,有人說它是“隱式傳遞的對(duì)象引用”,其實(shí)只要摸清它的綁定規(guī)則,就能輕松駕馭!今天就結(jié)合具體代碼實(shí)例,從“為什么有this”到“怎么用this”,一步步把this講透~

一、先搞懂:為什么要有this?

很多新手會(huì)疑惑,明明可以直接通過對(duì)象名訪問屬性,為什么還要用this?其實(shí)this的核心作用,是提供一種更優(yōu)雅的方式,隱式傳遞對(duì)象引用,讓代碼更簡(jiǎn)潔、更易于復(fù)用。

我們來看兩組對(duì)比代碼,一眼就能明白this的優(yōu)勢(shì):

// 沒有this的寫法,需要手動(dòng)傳遞對(duì)象
function identify(context) {
  return context.name.toUpperCase()
}
function speek(context) {
  var greeting = 'hello, I am ' + identify(context)
  console.log(greeting); // 輸出:hello, I am TOM
}
var me = { name: 'Tom' }
speek(me) // 每次調(diào)用都要手動(dòng)傳入me對(duì)象
// 有this的寫法,無需手動(dòng)傳遞,更簡(jiǎn)潔
function identify() {
  return this.name.toUpperCase() // this自動(dòng)指向調(diào)用者
}
function speek() {
  var greeting = 'Hello, I am ' + identify.call(this)
  console.log(greeting); // 輸出:Hello, I am TOM
}
var me = { name: 'Tom' }
speek.call(me) // 用call綁定this,無需重復(fù)傳參

不難發(fā)現(xiàn),有了this,我們不用每次調(diào)用函數(shù)都手動(dòng)傳遞對(duì)象,尤其在復(fù)雜項(xiàng)目中,能大大簡(jiǎn)化代碼,提升可讀性和復(fù)用性

二、this用在哪??jī)纱蠛诵膱?chǎng)景

this不是固定不變的,它的指向完全取決于“調(diào)用方式”,而不是“定義位置”。它主要用在兩個(gè)場(chǎng)景中,記住這兩點(diǎn),就能快速定位this的指向:

1. 全局作用域中的this

在全局作用域(不在任何函數(shù)內(nèi)部)中,this直接指向window對(duì)象(瀏覽器環(huán)境下)。哪怕是單獨(dú)的代碼塊,this依然指向window哦~

{
  let a = this
  console.log(a); // 輸出:Window 對(duì)象(瀏覽器環(huán)境)
}
// 全局作用域直接打印this
console.log(this === window); // 輸出:true

2. 函數(shù)作用域中的this

這是this最常用的場(chǎng)景,也是最容易踩坑的地方。函數(shù)中的this,指向調(diào)用該函數(shù)的對(duì)象,不同的調(diào)用方式,this的指向完全不同。接下來我們重點(diǎn)講解函數(shù)中this的5種綁定規(guī)則,每一種都搭配你提供的代碼實(shí)例,逐句解析~

三、this的5種綁定規(guī)則

規(guī)則1:默認(rèn)綁定 → 獨(dú)立調(diào)用的函數(shù),this指向window

當(dāng)函數(shù)被“獨(dú)立調(diào)用”(沒有任何上下文對(duì)象,直接調(diào)用)時(shí),this默認(rèn)綁定到window。哪怕函數(shù)嵌套在其他函數(shù)中,只要是獨(dú)立調(diào)用,this依然指向window。

// 實(shí)例1:直接調(diào)用函數(shù)
var a = 1
function foo() {
  console.log(this.a); // this指向window,window.a = 1
}
function bar () {
  var a = 2
  foo() // 獨(dú)立調(diào)用foo,this不指向bar,依然指向window
}
bar() // 輸出:1 ?
// 實(shí)例2:嵌套函數(shù)獨(dú)立調(diào)用
var a = 1
function bar () {
  var a = 2
  function foo() {
    console.log(this.a); // 獨(dú)立調(diào)用,this指向window
  }
  foo() // 獨(dú)立調(diào)用foo
bar() // 輸出:1 ?
// 實(shí)例3:無上下文調(diào)用函數(shù)
function foo() {
  var a = 1
  bar(this.a) // this指向window,window.a未定義,所以傳遞undefined
}
function bar(x) {
  console.log(x); // 輸出:undefined ?
}
foo() // 獨(dú)立調(diào)用foo,this指向window

規(guī)則2:隱式綁定 → 上下文對(duì)象調(diào)用,this指向該對(duì)象

當(dāng)函數(shù)被“上下文對(duì)象”調(diào)用時(shí)(比如:對(duì)象.函數(shù)()),this會(huì)隱式綁定到這個(gè)上下文對(duì)象上。簡(jiǎn)單說:誰調(diào)用函數(shù),this就指向誰。

// 實(shí)例1:對(duì)象直接調(diào)用函數(shù)
function foo() {
  console.log(this.a); // this指向調(diào)用者obj
}
var obj = {
  a: 1,
  foo: foo // foo作為obj的屬性
}
obj.foo() // 調(diào)用者是obj,輸出:1
// 實(shí)例2:多層對(duì)象調(diào)用(this指向最近的調(diào)用者)
function foo() {
  console.log(this.a);
}
var obj = {
  a: 1,
  foo: foo
}
var obj2 = {
  a: 2,
  foo: obj // obj2的foo屬性指向obj
}
obj2.foo.foo() // 最終調(diào)用foo的是obj,this指向obj,輸出:1

規(guī)則3:隱式丟失 → 函數(shù)引用被賦值,this指向“意外對(duì)象”

隱式丟失是最容易踩坑的情況!當(dāng)函數(shù)的引用被賦值給另一個(gè)變量,或者作為參數(shù)傳遞時(shí),原本的隱式綁定會(huì)失效,this會(huì)回歸默認(rèn)綁定(指向window)。

// 實(shí)例:函數(shù)引用被賦值,隱式丟失
function foo() {
  console.log(this.a);
}
var obj = {
  a: 1,
  foo: foo
}
// 把obj.foo賦值給變量bar,此時(shí)bar是獨(dú)立函數(shù)引用
var bar = obj.foo
var a = 2 // window.a = 2
bar() // 獨(dú)立調(diào)用bar,this指向window,輸出:2 (原本以為指向obj,實(shí)際丟失綁定)

簡(jiǎn)單總結(jié):只要函數(shù)不是被“對(duì)象.函數(shù)()”直接調(diào)用,而是被賦值后調(diào)用,大概率會(huì)發(fā)生隱式丟失哦~

規(guī)則4:顯式綁定 → 主動(dòng)綁定this,精準(zhǔn)控制指向

當(dāng)我們想主動(dòng)控制this的指向時(shí),就可以用顯式綁定——通過call、apply、bind三個(gè)方法,手動(dòng)將this綁定到指定對(duì)象上。這三個(gè)方法的用法有細(xì)微區(qū)別,結(jié)合實(shí)例一次性搞懂:

// 共同前提
var obj = { a: 1 }
function foo(x, y) {
  console.log(this.a, x + y); // this指向我們手動(dòng)綁定的obj
}
// 1. call方法:直接調(diào)用函數(shù),參數(shù)逐個(gè)傳遞
foo.call(obj, 1, 2) // 輸出:1 3 ?(call綁定this為obj,參數(shù)1、2逐個(gè)傳入)
// 2. apply方法:直接調(diào)用函數(shù),參數(shù)以數(shù)組形式傳遞
var arr = [1, 2]
foo.apply(obj, arr) // 輸出:1 3 ?(apply參數(shù)是數(shù)組,會(huì)自動(dòng)解構(gòu))
// 3. bind方法:不直接調(diào)用函數(shù),返回一個(gè)“綁定了this”的新函數(shù)
const bar = foo.bind(obj, 2, 4) // 綁定this為obj,預(yù)設(shè)參數(shù)2、4
bar(3) // 調(diào)用新函數(shù),額外傳入?yún)?shù)3,最終x=2,y=4+3=7?不!注意:bind預(yù)設(shè)參數(shù)在前
// 正確解析:bind預(yù)設(shè)的2、4是前兩個(gè)參數(shù),bar(3)是第三個(gè)參數(shù)?不,foo只有x、y兩個(gè)參數(shù)
// 最終x=2,y=4,輸出:1 6 ?(bind綁定后,參數(shù)會(huì)固定,后續(xù)傳入的參數(shù)會(huì)忽略多余的)

小技巧:call和apply的區(qū)別只在參數(shù)傳遞方式,bind和前兩者的區(qū)別是“不立即調(diào)用”,適合需要延遲調(diào)用的場(chǎng)景(比如定時(shí)器、事件綁定)。

規(guī)則5:new綁定 → 構(gòu)造函數(shù)中,this指向?qū)嵗龑?duì)象

當(dāng)用new關(guān)鍵字調(diào)用構(gòu)造函數(shù)時(shí),this會(huì)綁定到“新創(chuàng)建的實(shí)例對(duì)象”上。這也是構(gòu)造函數(shù)能創(chuàng)建多個(gè)實(shí)例的核心原因,我們結(jié)合你提供的代碼,解析new的底層邏輯和特殊情況:

// 實(shí)例1:正常new調(diào)用,this指向?qū)嵗?
function Animal() {
  this.name = '米奇' // this指向new創(chuàng)建的實(shí)例p
}
let a = new Animal()
let a2 = new Animal()
console.log(a.name); // 輸出:米奇 ?(a是實(shí)例,this指向a)
console.log(a2.name); // 輸出:米奇 ?(a2是另一個(gè)實(shí)例,this指向a2)
// 實(shí)例2:特殊情況——構(gòu)造函數(shù)return引用類型,new綁定失效(如果renturn 原始對(duì)象,對(duì)new的綁定不影響)
function Animal() {
  this.name = '米奇'
  return 123 // return的是原始類型
}
let a = new Animal()
console.log(a); // 輸出:Animal { name: '米奇' } ?
console.log(a.name); // 輸出:米奇 ?
function Animal() {
  this.name = '米奇'
  return {b: 1} // return的是引用類型(對(duì)象)
}
let a2 = new Animal()
console.log(a2); // 輸出:{b: 1} ?(new綁定失效,返回return的對(duì)象)
console.log(a2.name); // 輸出:undefined ?(a2不再是Animal實(shí)例,沒有name屬性)

補(bǔ)充new的底層原理(對(duì)應(yīng)你代碼中的注釋),幫你徹底理解:

  • 創(chuàng)建一個(gè)空對(duì)象(var obj = {});
  • 將構(gòu)造函數(shù)的this綁定到這個(gè)空對(duì)象(Animal.call(obj));
  • 給空對(duì)象添加屬性(obj.name = '米奇');
  • 將空對(duì)象的原型指向構(gòu)造函數(shù)的原型(obj.__proto__ = Animal.prototype);
  • 如果構(gòu)造函數(shù)沒有return,或者return的是基本類型,就返回這個(gè)空對(duì)象(實(shí)例);如果return的是引用類型,就返回這個(gè)引用類型。

四、特殊情況:箭頭函數(shù)中的this

箭頭函數(shù)是ES6新增的語法,它和普通函數(shù)最大的區(qū)別的是:箭頭函數(shù)沒有自己的this!箭頭函數(shù)中的this,永遠(yuǎn)指向它“外層最近的非箭頭函數(shù)”的this,而且一旦綁定,就無法修改(call、apply、bind也沒用)。

function foo() {
  var bar = () => {
    this.a = 2 // 箭頭函數(shù)沒有this,指向外層非箭頭函數(shù)foo的this
  }
  bar()
}
var obj = {
  a: 1,
  baz: foo
}
obj.baz() // 調(diào)用foo,foo的this指向obj(隱式綁定)
console.log(obj); // 輸出:{a: 2, baz: ?} ?(箭頭函數(shù)的this指向obj,修改了obj.a)
// 驗(yàn)證:箭頭函數(shù)this無法修改
var obj2 = {a: 3}
bar.call(obj2) // 試圖用call修改this,無效
console.log(obj.a); // 依然是2 ?
console.log(obj2.a); // 還是3 ?

小提醒:箭頭函數(shù)適合用在回調(diào)函數(shù)中(比如定時(shí)器、數(shù)組方法),可以避免this指向混亂;但不適合用在構(gòu)造函數(shù)中,因?yàn)樗鼪]有自己的this,無法創(chuàng)建實(shí)例哦~

五、總結(jié):this指向判斷口訣

看完上面的規(guī)則,可能會(huì)覺得有點(diǎn)多,教大家一個(gè)簡(jiǎn)單的判斷口訣,遇到this就按這個(gè)順序來,永遠(yuǎn)不會(huì)錯(cuò):

  • 看函數(shù)是不是用new調(diào)用?是 → this指向?qū)嵗?/li>
  • 看函數(shù)是不是用call、apply、bind調(diào)用?是 → this指向綁定的對(duì)象;
  • 看函數(shù)是不是被上下文對(duì)象調(diào)用(對(duì)象.函數(shù)())?是 → this指向該對(duì)象;
  • 看函數(shù)是不是箭頭函數(shù)?是 → this指向外層最近的非箭頭函數(shù)的this;
  • 以上都不是 → 默認(rèn)綁定,this指向window(嚴(yán)格模式下是undefined)。

到此這篇關(guān)于JavaScript this綁定規(guī)則:告別踩坑指南的文章就介紹到這了,更多相關(guān)JavaScript this綁定規(guī)則內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

宝清县| 洞口县| 冷水江市| 秦安县| 克拉玛依市| 淮滨县| 临沧市| 眉山市| 县级市| 若尔盖县| 长岭县| 盐源县| 莱阳市| 乐安县| 谢通门县| 璧山县| 凯里市| 江陵县| 大荔县| 湖南省| 根河市| 松溪县| 乌鲁木齐市| 宣威市| 麻阳| 即墨市| 甘德县| 木兰县| 班玛县| 溧阳市| 公主岭市| 喀什市| 淄博市| 南汇区| 柳江县| 从江县| 绥芬河市| 无为县| 曲靖市| 武邑县| 花莲市|