深入了解JavaScript中的this關(guān)鍵字指向
全局作用域的this
- 游覽器:非嚴(yán)格模式指向window,嚴(yán)格模式指向undefined
- Node環(huán)境:指向{}
- 把文件看作module -> 加載編譯 -> 放到一個(gè)函數(shù)中 -> 通過 apply({})/call({}) 執(zhí)行這個(gè)函數(shù)
調(diào)用方式不同,this指向不同
在大多情況下,this出現(xiàn)在函數(shù)中。this指向什么,跟函數(shù)定義的位置無關(guān),跟函數(shù)調(diào)用方式有關(guān)(綁定規(guī)則相關(guān))。
function foo(){ console.log(this); } var obj = { foo: foo } //不同的調(diào)用方式this的指向不同,不同的調(diào)用方式對(duì)應(yīng)著不同的綁定規(guī)則 foo();//window obj.foo();//obj foo.call("123");//String{"abc"}
this的綁定規(guī)則
- 默認(rèn)綁定:函數(shù)獨(dú)立調(diào)用方式,this指向全局對(duì)象
- 隱式綁定:通過對(duì)象調(diào)用方法,會(huì)隱式的將this指向當(dāng)前對(duì)象
- 顯示綁定:通過函數(shù)的apply、call、bind方法改變函數(shù)中this的指向
- apply/call:會(huì)自動(dòng)調(diào)用,第一個(gè)參數(shù)都是設(shè)置this的指向,apply第二個(gè)參數(shù)為數(shù)組,call后面?zhèn)魅霝閰?shù)列表。
- bind:不會(huì)自動(dòng)調(diào)用,會(huì)返回一個(gè)已經(jīng)綁定好this的函數(shù),傳參與call一樣
- new綁定 :通過new關(guān)鍵字調(diào)用函數(shù),new 函數(shù)()
- 創(chuàng)建一個(gè)全新的對(duì)象
- 這個(gè)新對(duì)象會(huì)被執(zhí)行prototype連接
- 執(zhí)行構(gòu)造函數(shù)中的代碼,為新對(duì)象添加屬性(this綁定在這個(gè)步驟完成)
- 如果函數(shù)沒有返回其他對(duì)象,表達(dá)式會(huì)返回這個(gè)新對(duì)象
this綁定優(yōu)先級(jí)(權(quán)重)
- 示綁定(bind>call/apply) > 隱式綁定 > 默認(rèn)綁定
function fn() { console.log(this); } fn.bind(123).apply(321);
- new 綁定 > 隱式綁定 > 默認(rèn)綁定
- new 綁定 > 顯示綁定(通過bind綁定this的函數(shù),可以被new關(guān)鍵字改變this指向)
function Fn(){ console.log(this); } fn.bind("132"); var obj = new Fn();
- new關(guān)鍵字不能和call/apply一起使用,因?yàn)閚ew會(huì)主動(dòng)調(diào)用函數(shù),call/apply也會(huì)主動(dòng)調(diào)用函數(shù),這樣會(huì)產(chǎn)生沖突報(bào)錯(cuò)
綁定優(yōu)先級(jí):new 綁定 > 顯示綁定 > 隱式綁定 > 默認(rèn)綁定
this規(guī)則之外
忽略顯示綁定
apply/call/bind:當(dāng)傳入null/undefined時(shí),自動(dòng)將this綁定成全局對(duì)象
function fn(){ console.log(this); } fn.apply(null); fn.apply(undefined);
間接函數(shù)引用
var obj1 = { foo: function(){ console.log(this); } } var obj2 = {} ;(obj2.bar = obj1.foo)()//括號(hào)中包含賦值表達(dá)式,屬于獨(dú)立函數(shù)調(diào)用,是默認(rèn)綁定,指向window
箭頭函數(shù) 將頭函數(shù)不會(huì)綁定this,arguments屬性箭頭函數(shù)不能作為構(gòu)造函數(shù)來使用(不能new對(duì)象) 簡(jiǎn)寫
- 簡(jiǎn)寫一:當(dāng)參數(shù)只有一個(gè),可以省略括號(hào)
- 簡(jiǎn)寫二:當(dāng)函數(shù)體只有一行,可以省略大括號(hào),并且會(huì)將這一行代碼的返回值return
var nums = [0, 1, 2, 3, 4, 5]; var result = nums .filter(item => item % 2 === 0) .map(item => item * 10) .reduce((preVal, curVal) => preVal + curVal, 0); console.log(result);
- 簡(jiǎn)寫三:如果只有一個(gè)行,且需要返回一個(gè)對(duì)象,那么要將對(duì)象用括號(hào)包裹。因?yàn)槭÷?quot;{}“后,不知道將對(duì)象的”{}"如何解析
var foo = () => ({ name: "foo", age: 18 });//這樣解析時(shí)會(huì)將對(duì)象當(dāng)作一個(gè)整體
箭頭函數(shù)的this綁定
箭頭函數(shù)不遵循this的四種標(biāo)準(zhǔn)規(guī)則,箭頭函數(shù)內(nèi)部沒有綁定this,也不能通過call/apply/bind綁定this,箭頭函數(shù)的this指向根據(jù)外層作用域決定
var obj = { getData() { setTimeout(function () { console.log(this); }, 200); }, }; //setTimeout中的函數(shù)屬于獨(dú)立調(diào)用,所以指向的是window //如果想讓this指向obj對(duì)象,setTimeout中使用箭頭函數(shù) obj.getData();
this相關(guān)面試題
面試題一:
var name = "window"; var person = { name: "person", sayName: function () { console.log(this.name); } }; function sayName() { var sss = person.sayName; sss(); person.sayName(); (person.sayName)(); (b = person.sayName)(); //包含賦值表達(dá)式,屬于間接函數(shù)引用 } sayName();
答案:window(默認(rèn)綁定)、person(隱式綁定)、person(隱式綁定)、window(間接函數(shù)引用)
面試題二:
var name = 'window' var person1 = { name: 'person1', foo1: function () { console.log(this.name) }, foo2: () => console.log(this.name), foo3: function () { return function () { console.log(this.name) } }, foo4: function () { return () => { console.log(this.name) } } } var person2 = { name: 'person2' } person1.foo1(); person1.foo1.call(person2); person1.foo2(); person1.foo2.call(person2); person1.foo3()(); person1.foo3.call(person2)(); person1.foo3().call(person2); person1.foo4()(); person1.foo4.call(person2)(); person1.foo4().call(person2);
答案解析:
person1.foo1(); //person1:隱式綁定 person1.foo1.call(person2); //person2:顯示綁定 person1.foo2();//window:箭頭函數(shù)的this指向上層作用域的this person1.foo2.call(person2);//window:箭頭函數(shù)的this指向上層作用域的this,且不能改變箭頭函數(shù)指向 person1.foo3()();//window:先執(zhí)行person1.foo3(),然后拿到返回的函數(shù)再調(diào)用,屬于獨(dú)立調(diào)用,所以指向window person1.foo3.call(person2)();//window:先執(zhí)行person1.foo3.call(person2),拿到返回的函數(shù)再調(diào)用,屬于獨(dú)立調(diào)用 person1.foo3().call(person2);//person2:先執(zhí)行person1.foo3(),拿到返回的函數(shù)通過call調(diào)用this指向了person2 person1.foo4()(); //person1:拿到返回的箭頭函數(shù)后,箭頭函數(shù)沒有this,根據(jù)上層作用域決定,上層foo4函數(shù)指向的是person1對(duì)象(foo4是被person1直接調(diào)用的),所以內(nèi)部箭頭函數(shù)也指向peroson1 person1.foo4.call(person2)(); //person2:給foo4綁定this為person2,箭頭函數(shù)調(diào)用this指向上層作用域,上層foo4的this被顯示綁定為了person2,那么內(nèi)部的箭頭函數(shù)也是指向person2 person1.foo4().call(person2); //person1:call調(diào)用箭頭函數(shù),依然去上一層找,所以依然是person1
面試題三:
var name = 'window' function Person (name) { this.name = name this.foo1 = function () { console.log(this.name) }, this.foo2 = () => console.log(this.name), this.foo3 = function () { return function () { console.log(this.name) } }, this.foo4 = function () { return () => { console.log(this.name) } } } var person1 = new Person('person1') var person2 = new Person('person2') person1.foo1() person1.foo1.call(person2) person1.foo2() person1.foo2.call(person2) person1.foo3()() person1.foo3.call(person2)() person1.foo3().call(person2) person1.foo4()() person1.foo4.call(person2)() person1.foo4().call(person2)
答案與解析:
person1.foo1() //person1 person1.foo1.call(person2) //person2 person1.foo2() //person1:箭頭函數(shù),指向上層作用域的this,上層作用域是“Person構(gòu)造函數(shù)” person1.foo2.call(person2) //person1::箭頭函數(shù),指向上層作用域的this,不能被顯示綁定 person1.foo3()() //window:拿到返回的函數(shù)后調(diào)用,屬于獨(dú)立調(diào)用 person1.foo3.call(person2)() //window:拿到返回的函數(shù)后調(diào)用,屬于獨(dú)立調(diào)用 person1.foo3().call(person2) //person2:通過call顯示綁定 person1.foo4()() //person1:返回的箭頭函數(shù)去上層作用域找,上層foo的this指向person1 person1.foo4.call(person2)()//person2:返回的箭頭函數(shù)去上層作用域找,上層this通過call指向了person2 person1.foo4().call(person2)//person1:箭頭函數(shù)的this不能被顯示綁定
面試題四:
var name = 'window' function Person (name) { this.name = name this.obj = { name: 'obj', foo1: function () { return function () { console.log(this.name) } }, foo2: function () { return () => { console.log(this.name) } } } } var person1 = new Person('person1') var person2 = new Person('person2') person1.obj.foo1()() person1.obj.foo1.call(person2)() person1.obj.foo1().call(person2) person1.obj.foo2()() person1.obj.foo2.call(person2)() person1.obj.foo2().call(person2)
答案與解析:
person1.obj.foo1()() //window:獨(dú)立調(diào)用 person1.obj.foo1.call(person2)() //window:獨(dú)立調(diào)用 person1.obj.foo1().call(person2) //person2:call顯示綁定 person1.obj.foo2()() //obj:返回的是箭頭函數(shù),this由上層作用域foo2函數(shù)決定,foo2的this指向obj(foo2是被obj直接調(diào)用的),所以返回的箭頭函數(shù)this也是指向obj person1.obj.foo2.call(person2)()//person2:箭頭函數(shù)上層作用域this被call指向person2,所以箭頭函數(shù)也是指向person2 person1.obj.foo2().call(person2)//obj:箭頭函數(shù)this不能被顯示綁定
到此這篇關(guān)于深入了解JavaScript中的this關(guān)鍵字指向的文章就介紹到這了,更多相關(guān)JavaScript中的this內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript原生對(duì)象之Date對(duì)象的屬性和方法詳解
這篇文章主要介紹了JavaScript原生對(duì)象之Date對(duì)象的屬性和方法詳解,需要的朋友可以參考下2015-03-03Javascript操作dom對(duì)象之select全面解析
下面小編就為大家?guī)硪黄狫avascript操作dom對(duì)象之select全面解析。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04Javascript中的數(shù)學(xué)函數(shù)
Javascript中的數(shù)學(xué)函數(shù)...2007-04-04JavaScript起點(diǎn)(嚴(yán)格模式深度了解)
嚴(yán)格模式(Strict Mode)是ECMAScript5新增的功能,目前所有的主流瀏覽器的最新版本——包括IE10與Opera12——都支持嚴(yán)格模式,感興趣的朋友可以了解下啊,希望本文對(duì)你有所幫助2013-01-01實(shí)例講解JavaScript中的this指向錯(cuò)誤解決方法
JavaScript中this指向的處理是令大家普遍頭疼的問題,這里我們舉一個(gè)實(shí)例講解JavaScript中的this指向錯(cuò)誤解決方法,需要的朋友可以參考下2016-06-06簡(jiǎn)介JavaScript中setUTCSeconds()方法的使用
這篇文章主要介紹了簡(jiǎn)介JavaScript中setUTCSeconds()方法的使用,是JS入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-06-06js中一維數(shù)組和二位數(shù)組中的幾個(gè)問題示例說明
這篇文章主要介紹了js中一維數(shù)組和二位數(shù)組中的幾個(gè)問題,并給出對(duì)應(yīng)的解決方法,需要的朋友可以參考下2014-07-07jQuery入門問答 整理的幾個(gè)常見的初學(xué)者問題
大家可能看到了,我已經(jīng)將過去寫的兩篇jQuery的教程刪掉了,因?yàn)楦郊淮嬖诹说鹊葐栴},所以刪除了,從今天開始我就寫jQuery教程第二版了!希望大家能夠支持我!2010-02-02