this 的指向問題

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。

this的指向已經是一個老生常談的問題,每逢面試都要去復習復習,近來鞏固js的基礎,決心徹底掌握這個知識點,一勞永逸。說明一下,為了不影響大家的思考過程,下面的代碼都不會去注釋答案,想知道答案,只需要去控制臺執行一下。

四類場景逐一擊破

首先,分析this的指向共有四種類型,在分析之前,我們首先帶好兩個錦囊:
1.函數被調用時(即運行時)才會確定該函數內this的指向。因為在函數中this與arguments是兩個特殊的變量,在函數被調用時才會取得它們,而且搜索這兩個變量時只會在活動對象范圍里面去搜。(有關活動對象與變量對象的知識,請移步到js 中的活動對象 與 變量對象 什么區別?)
2.要確定函數中this的指向,必須先找到該函數被調用的位置。

認準第一種“test()”形式

var a = 1
function test () {console.log(this.a)
}
test()

直接不帶任何引用形式去調用函數,則this會指向全局對象,因為沒有其他影響去改變this,this默認就是指向全局對象(瀏覽器是window,Node中是global)的。這個結論是在非嚴格模式的情況下,嚴格模式下這個this其實是undefined的。

認準第二種“xxx.test()”形式

var a = 1
function test () {console.log(this.a)
}
var obj = {a: 2,test
}
obj.test()

這種形式對比起第一種,很明顯test()已經是名花有主的了!看清楚,是誰呼喚的test()?沒錯,就是obj,所以this的指向就不言而喻了。一句話,誰去調用這個函數的,這個函數中的this就綁定到誰身上。

var a = 1
function test () {console.log(this.a)
}
var obj = {a: 2,test
}
var obj0 = {a: 3,obj 
}
obj0.obj.test()

即使是這種串串燒的形式,結果也是一樣的,test()中的this只對直屬上司(直接調用者obj)負責。再來看一個綜合點的例子:

var a = 1
function test () {console.log(this.a)
}
var obj = {a: 2,test
}
var testCopy = obj.test
testCopy()

嗯,聰明的你一定想到,換了個名字就能騙到我了!?雖然經過了一波改名換姓,但本質上還不是obj.test()嘛!結果一定和上面一樣!唔,請F12在控制臺試試,竟然……其實這里并不需要去思考什么,按照我們的套路,我們就認函數調時的樣子,有沒有看到最后調用的時候跟第一種情況一毛一樣?我再介紹一個場景大家一定不會覺得陌生:

var a = 1
function test () {console.log(this.a)
}
var obj = {a: 2,test
}
setTimeout(obj.test)

你可以意淫一下setTimeout的本質,是不是相當于有一個setTimeout函數,接收兩個參數:

function setTimeout (fn, time) {// 這里干了一大波不可描述的事情,最后會去調一下你傳進來的回調函數fn()
}

看到怎樣調用你傳進來的函數了嗎!?再想想我們第一種形式的標題認準第一種“test()”形式

認準第三種“test.call(xxx) / test.apply(xxx) / test.bind()”形式

看了上面兩種形式之后,你可能會想,我非常討厭上面那些矯情的扭扭捏捏的九曲十八彎的調用方式,讓人毫無安全感,我要我自己指定this的指向,我要勝天半子!沒問題,我的代碼我做主:

var a = 1
function test () {console.log(this.a)
}
var obj = {a: 2,test
}
var testCopy = obj.test
testCopy.call(obj)

可以看到,我們通過call(apply跟call的區別只是傳參,作用是一樣的,bind有點區別,bind能讓我們的函數延遲執行,apply與call調用就執行,所以bind這樣的形式我們也稱為函數柯里化,這些就不是我們這里要說的啦)來調用testCopy,并且傳入了你想要this指向的上下文,那么this就會乖乖按照你的指示行事啦。看到這里,我們也可以想象第一、二種形式其實可以轉化成call/apply的形式,有一篇比較棒的文章描述了這樣的思考過程,大家也可以看看this 的值到底是什么?一次說清楚

認準第四種“new test()”形式

終于到了最后一種形式了,這種形式比較好認,因為有標志性的new:

var a = 1
function test (a) {this.a = a
}
var b = new test(2)
console.log(b.a)

new這個操作符其實是new了一個新對象出來,而被new的test我們稱為構造函數,我們可以在這個構造函數里定義一下將要到來的新對象的一些屬性。那么在構造函數里,我們怎樣去描述這個還未出生的新對象呢?沒錯,就是用this。所以構造函數里的this指的就是將要被new出來的新對象。

One more thing

感謝大家看到這里,但還要說最后一種形式。等等,不是說好的只有四種形式嗎!稍安勿躁,正常套路下確實只有上面四種,但是有個東西別忘了,就是大家最喜歡的箭頭函數。

var a = 1
var test = () => {console.log(this.a)
}
var obj = {a: 2,test
}
obj.test()

來,往上翻一下我們的第一個錦囊,“函數被調用時(即運行時)才會確定該函數內this的指向。”現在函數這兩個字要加個詞修飾一下,變成普通函數(非箭頭函數)才能區別于箭頭函數。箭頭函數中的this在函數定義的時候就已經確定,它this指向的是它的外層作用域this的指向。

最后

我們最后還要說:“到此為止,真的沒有了。”
希望看完這篇文章之后,再有人問this指向的問題,你可以嘴角微微上揚,冷笑一聲:“不要再問我this的指向問題了。”
揚長而去。

轉自:https://segmentfault.com/a/1190000015438195

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

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

相關文章

C++之全局函數和成員函數的轉換

全局函數和成員函數 把全局函數轉化成成員函數,通過this指針隱藏左操作數 Test add(Test &t1, Test &t2)》Test add(Test &t2) 把成員函數轉換成全局函數,多了一個參數 void printAB()》void printAB(Test *pthis) 函數返回元素和返回引…

HDU 3916 Sequence Decomposition 【貪心】

這道題目的題意就是使用題目中所給的Gate 函數,模擬出輸入的結果 當然我們分析的時候可以倒著來,就是拿輸入去減 每次Gate 函數都會有一個有效范圍 這道題目求的就是,找出一種模擬方法,使得最小的有效范圍最大化。 是一道【貪心】…

爆胎

定義 即輪胎爆裂。車輛的缺氣(輪胎胎壓低于標準胎壓)行駛時,隨著胎壓的下降,輪胎與地面的摩擦成倍增加,胎溫急劇升高,輪胎變軟,強度急劇下降。這種情況下,如果車輛高速行駛,就可能導致爆胎。…

不要再問我跨域的問題了

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 跨域這兩個字就像一塊狗皮膏藥一樣黏在每一個前端開發者身上,無論你在工作上或者面試中無可避免會遇到這個問題。為了應付面…

SSM集合

SSM集成 1. Spring和各個框架的整合 Spring目前是JavaWeb開發中最終的框架,提供一站式服務,可以其他各個框架整合集成 Spring整合方案 1.1. SSH ssh是早期的一種整合方案 Struts2 : Web層框架 Spring : 容器框架 Hibernate &#…

淺談 CSRF 攻擊方式

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 一.CSRF是什么? CSRF(Cross-site request forgery),中文名稱:跨站請求偽造&a…

C++之運算符重載(上)

1、概念 所謂重載,就是重新賦予新的含義。函數重載就是對一個已有的函數賦予新的含義,使之實現新功能,因此,一個函數名就可以用來代表不同功能的函數,也就是”一名多用”。 運算符也可以重載。實際上,我們…

手剎

定義 考手剎的專業稱呼是輔助制動器,與制動器的原理不同,其是采用鋼絲拉線連接到后制動蹄上,以對車子進行制動。作用 用于平地斜坡停車時制動,防止車子在無人狀態下自動滑跑,逼免發生交通事故。工作原理 其原…

關于[super dealloc]

銷毀一個對象時,需要重寫系統的dealloc方法來釋放當前類所擁有的對象,在dealloc方法中需要先釋放當前類中所有的對象,然后再調用[super dealloc]釋放父類中所擁有的對象。如先調用[super dealloc]將釋放掉父類中所擁有的對象,當前…

C++之運算符重載(下)

4.提高 1.運算符重載機制 編譯器實現運算符重載實際上就是通過函數重載實現的,可分為全局函數方式,也可分為成員函數方式進行重載,并沒有改變原操作符的屬性和語義。只是針對某個特定類定義一種新的數據類型操作。 2.重載賦值運算符 賦值…

Cookie / Session 的機制與安全

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 Cookie和Session是為了在無狀態的HTTP協議之上維護會話狀態,使得服務器可以知道當前是和哪個客戶在打交道。本文來詳細討論C…

手動擋

定義 手動擋,即用手撥動變速桿才能改變變速器內的齒輪嚙合置,改變傳動比,從而達到變速的目的。作用 一方面提供了手動的樂趣 另外一方面就是通過手動自主控制轉速,還可以遲延或提前換檔。駕駛技巧 市區內應直視前方五…

Servlet快速入門及運行流程

一、Servlet快速入門 1.創建一個web工程 2.在JavaResource中src下創建一個包名稱為com.myxq.servlet 3.在創建的servlet包當中創建一個class文件起名為FirstServlet 4.進入該class實現一個Servlet接口,實現它未實現的方法 重點看service方法在該方法當中寫入一句話進…

C++之多繼承

1.基礎知識 1.1 類之間的關系 has-A,uses-A 和 is-A has-A 包含關系,用以描述一個類由多個“部件類”構成。實現has-A關系用類成員表示,即一個類中的數據成員是另一種已經定義的類。 常和構造函數初始化列表一起使用 uses-A 一個類部分地…

自動擋

定義 所謂自動擋,就是不用駕駛者去手動換檔,車輛會根據行駛的速度和交通情況自動選擇合適的檔位行駛。作用 能根據路面狀況自動變速,使駕駛者可以全神貫地注視路面交通而不會被換檔搞得手忙腳亂。工作原理 自動變速器&#xff0c…

聊一聊 cookie

我們看到的 cookie 前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 我自己創建了一個網站,網址為http://ppsc.sankuai.com。在這個網頁中我設置了幾個cookie:JS…

跨域資源共享 CORS 詳解

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。 它允許瀏覽…

油門

定義 油門是內燃機上控制燃料供量的裝置。作用 是汽車發動機與摩托車油箱之間的閥門,控制汽油的量。操作注意 1.空車起步勿用大油門,以小油門為宜,負荷起步則以中油門為宜。 2.啟動時將油門放在合適位,使機件不易磨損。…

C++之泛型編程(模板)

1.模板綜述 背景 有時候許多函數或子程序的邏輯結構是一樣的,只是要處理的數據類型不一樣有時候多個類具有相同邏輯的成員函數和成員變量,只是成員變量的數據類型以及成員函數的參數類型不一樣模板就是解決數據類型不一致造成代碼冗余的一種機制&#xf…

Base64轉PDF、PDF轉IMG(使用pdfbox插件)

--添加依賴 <!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox --><dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.12</version></dependency&…