細(xì)說JavaScript中的this指向與綁定規(guī)則
this的指向
通常在瀏覽器中,在全局中使用this,該this指向的是window對(duì)象,無論是否開啟了嚴(yán)格模式。但我們一般使用this,也是在函數(shù)中進(jìn)行使用。所有的函數(shù)在被調(diào)用的時(shí)候,會(huì)產(chǎn)生一個(gè)函數(shù)執(zhí)行上下文,該上下文中記錄這函數(shù)的作用域鏈、AO對(duì)象以及當(dāng)前這個(gè)函數(shù)的this指向。我們看下面代碼:
function foo() { console.log(this) } foo()//window var obj = { name: 'why', foo: foo } obj.foo()//obj foo.apply("abc")//String{'abc'}
上面代碼中,我們定義了一個(gè)函數(shù)foo來輸出調(diào)用它的時(shí)候this的指向,從上往下分別指向的是window、obj、String{'abc'},所以我們可以知道:
- 函數(shù)在調(diào)用時(shí),JavaScript會(huì)默認(rèn)給this綁定一個(gè)值;
- this的綁定和定義的位置(編寫的位置)沒有關(guān)系;
- this的綁定和調(diào)用方式以及調(diào)用的位置有關(guān)系;
- this是在運(yùn)行時(shí)被動(dòng)態(tài)綁定的,而不是編譯時(shí)固定下來的
判斷this綁定的4條規(guī)則
規(guī)則1:默認(rèn)綁定
獨(dú)立函數(shù)調(diào)用的時(shí)候,this永遠(yuǎn)綁定的是window對(duì)象,如下示例:
function foo() { console.log(this) } function foo2() { foo() } var obj = { name: "xiaomin", foo: function() { console.log(this) } } foo()//window foo2()//window var bar = obj.foo bar()//window
規(guī)則2:隱式綁定
通過某個(gè)對(duì)象發(fā)起調(diào)用的函數(shù),哪個(gè)對(duì)象發(fā)起調(diào)用的函數(shù),那么該調(diào)用函數(shù)的this就隱式綁定在了這個(gè)對(duì)象:
var obj1 = { name: "obj1", foo: function () { console.log(this); }, }; var obj2 = { name: "obj2", bar: obj1.foo, obj1: obj1, }; obj1.foo();//obj1 obj2.obj1.foo();//obj1 obj2.bar();//obj2
規(guī)則3:顯示綁定
通過函數(shù)的方法call、apply、bind將this顯示綁定了某個(gè)對(duì)象上,那么該函數(shù)的this就指向到這個(gè)對(duì)象上:
function foo() { console.log(this) } var obj = { name: "obj" } foo.call(obj) foo()//obj foo.apply(obj) foo()//obj var newfoo = foo.bind(obj) newfoo()//obj
規(guī)則4:new綁定
我們有如下代碼:
function Person(name, age) { this.name = name this.age = age console.log(this)//p } var p = new Person("kobe",12);
在這里我們有一個(gè)構(gòu)造函數(shù)Person,并用它創(chuàng)建了一個(gè)對(duì)象,這里簡單說明一下通過new調(diào)用構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí)的5個(gè)步驟:
- 在內(nèi)存中創(chuàng)建一個(gè)空對(duì)象
- 將該對(duì)象的[[prototype]]指向構(gòu)造函數(shù)的prototype屬性
- 構(gòu)造函數(shù)里的this指向這個(gè)空對(duì)象
- 開始執(zhí)行構(gòu)造函數(shù)的函數(shù)體代碼
- 如果構(gòu)造函數(shù)未返回內(nèi)容,將該對(duì)象作為返回值返回出去
從上面我們可以看到,在使用new創(chuàng)建對(duì)象的時(shí)候,在第三個(gè)步驟會(huì)將構(gòu)造函數(shù)內(nèi)部的this綁定到創(chuàng)建的這個(gè)對(duì)象上,也就是上面代碼中,Person函數(shù)中打印的this就是會(huì)是通過new關(guān)鍵字創(chuàng)建的對(duì)象p。
this綁定的優(yōu)先級(jí)
當(dāng)同時(shí)出現(xiàn)上列規(guī)則的多種規(guī)則綁定的時(shí)候,這時(shí)候this的指向就會(huì)根據(jù)上面綁定規(guī)則的優(yōu)先級(jí)進(jìn)行綁定:
- 默認(rèn)綁定優(yōu)先級(jí)最低
- 顯示綁定優(yōu)先于隱式綁定,如下列代碼打印的this就不是obj而是String {'aaa'}
function foo() { console.log(this);//String?{'aaa'} } var obj = { name: "obj", foo: foo.bind("aaa"), }; obj.foo();
- new綁定優(yōu)先于隱式綁定,如下列代碼打印出來的就不是obj,而是創(chuàng)建出來的對(duì)象f
var obj = { name: "obj", foo: function () { this.name = "kkk"; console.log("this:", this);//foo?{name: 'kkk'} }, }; var f = new obj.foo();
- new綁定優(yōu)先bind綁定(new綁定不能同時(shí)與call、apply同時(shí)使用),如下代碼this打印出來的就是obj的對(duì)象而不是String{'aaa'}
function foo() { console.log(this); } var bar = foo.bind("aaa"); var obj = new bar(); //var obj2 = new foo.apply("123");//這樣寫會(huì)報(bào)錯(cuò)
除了四個(gè)this綁定規(guī)則外的特殊情況
1、在顯示綁定中我們綁定了null或者undefined,this會(huì)綁定到window上
function foo() { console.log(this) } foo.call({})//{} foo.call(null)//window foo.call(undefined)//window
2、函數(shù)的間距引用,在下列代碼中,賦值表達(dá)式 p.foo = o.foo 的返回值是目標(biāo)函數(shù)的引用,因此調(diào)用位置是 foo(),不是o.foo()。所以打印出來的this是window而不是o或者p
function foo() { console.log(this); } var o = { foo: foo }; var p = {}; o.foo(); // o (p.foo = o.foo)(); // window
3、箭頭函數(shù)。箭頭函數(shù)是不會(huì)有自己的this的,在調(diào)用箭頭函數(shù)的時(shí)候,在它的函數(shù)執(zhí)行上下文中并不會(huì)生成它this的記錄,而如果在箭頭函數(shù)的函數(shù)體中使用到了this,那么它將會(huì)在它的上層作用域里面去找this,看下面代碼
var obj = { data: [], changeData: function () { console.log("普通函數(shù)this:", this); (() => { console.log("箭頭函數(shù)this:", this); })(); setTimeout(() => { this.data = ["1", "2", "3"]; console.log("this:", this); }, 1000); }, }; obj.changeData();
打印結(jié)果:
可以看出,上面打印的this其實(shí)都是指向的obj。在箭頭函數(shù)內(nèi)它自身沒有this,那么它就向外層尋找,找到了changeData這個(gè)函數(shù),而這時(shí)由于隱式綁定規(guī)則,changeData由obj調(diào)用的,那么changeData的this就指向的obj,所以箭頭函數(shù)的this指向的就是obj。
以上就是細(xì)說JavaScript中的this指向與綁定規(guī)則的詳細(xì)內(nèi)容,更多關(guān)于JavaScript this的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript中的object轉(zhuǎn)換成number或string規(guī)則介紹
這篇文章主要介紹了JavaScript中的object轉(zhuǎn)換成number或string規(guī)則介紹,本文講解了object自動(dòng)轉(zhuǎn)換成string的規(guī)則、object自動(dòng)轉(zhuǎn)換成number的規(guī)則等內(nèi)容,需要的朋友可以參考下2014-12-12JavaScript如何判斷一個(gè)對(duì)象是空對(duì)象(附5種常見方法)
在JavaScript中判斷對(duì)象的類型是開發(fā)過程中的一個(gè)常見需求,尤其是在處理不確定類型的數(shù)據(jù)時(shí),這篇文章主要介紹了JavaScript如何判斷一個(gè)對(duì)象是空對(duì)象的相關(guān)資料,需要的朋友可以參考下2025-04-04微信小程序?qū)崿F(xiàn)收藏與取消收藏切換圖片功能
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)收藏與取消收藏切換圖片功能,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-08-08解決window.opener=null;window.close(),只支持IE6不支持IE7,IE8的問題
本篇文章主要是對(duì)window.opener=null;window.close(),只支持IE6不支持IE7,IE8的解決方法進(jìn)行了介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助2014-01-01ES6實(shí)現(xiàn)的遍歷目錄函數(shù)示例
這篇文章主要介紹了ES6實(shí)現(xiàn)的遍歷目錄函數(shù),涉及ES6文件目錄的遍歷、讀取、回調(diào)函數(shù)及json相關(guān)操作技巧,需要的朋友可以參考下2017-04-04微信公眾號(hào)平臺(tái)接口開發(fā) 獲取access_token過程解析
這篇文章主要介紹了微信公眾號(hào)平臺(tái)接口開發(fā) 獲取access_token過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08