觀感度:🌟🌟🌟🌟🌟javascript
口味:清爽綠豆前端
烹飪時間:15minjava
你皮任你皮,我當你瓜皮。node
衆所周知,this
在JavaScript中的指向一直很難讓人理解,想要學好JavaScript,this
也是咱們必需要搞清楚的。其實,this
並無那麼難,本文將力爭帶你治療this
的「皮」。瀏覽器
首先,來科普三個問題!app
this
是聲明函數時附加的參數,指向特定的對象,也就是隱藏參數。函數
好比LOL中各類隱藏的彩蛋,當水晶先鋒斯卡納在草叢裏停留超過15秒不動,會模仿寵物小精靈。this
「皮卡!皮卡!皮卡丘!」spa
「斯卡!斯卡!斯卡納!」 prototype
好,相信你們已經理解什麼是this
了,就是個隱藏參數,沒有多麼的神奇,其實 每一個函數均可以訪問this
。
this
提供了一種更加優雅的方式來隱式的傳遞對象引用。
通俗地說:就是說咱們能夠把API設計的更加簡潔並且易於複用。
說人話:那就是this
能夠幫咱們省略參數。
只須要理解並記住一句話,外加幾種小狀況,你們就能夠完徹底全的理解this
。
好,注意聽講。
這句話就是「this
的指向在函數聲明的時候是不會被肯定的,只有函數執行的時候才被肯定,this
最終指向的是調用它的對象」。
有人說這也太長了,記不住。
好,那縮短點。
一句話。
「this
的指向決定於函數的調用方式」。
總結:
1.this
是聲明函數時附加的參數,指向特定的對象,也就是隱藏參數。2.
this
能夠幫咱們省略參數。3.
this
的指向決定於函數的調用方式。
是否是很簡單,搞清楚了這三點,咱們下面將從八種狀況來完全理解this
的指向問題。
直接上代碼。
對,沒錯,有沒有想起灌籃高手主題曲
咱們首先要了解一下世界觀,分爲三種狀況。
1.在非嚴格模式下,瀏覽器中的盡頭固然就是window
。2.在嚴格模式下也就是開啓了
"use strict"
的狀況下,盡頭就是undefined
。3.
node
的全局環境中盡頭是global
。
下文中狀況主要從第一種非嚴格模式下來對this
的指向進行解釋和說明。
// 咱們來看下面的兩個🌰。 function demo(){ var user = 「前端食堂」; console.log(this.user); // undefined console.log(this); // window } demo(); // 這裏的函數demo其實是被window對象使用點語法所點出來的,以下: function demo(){ var user = 「前端食堂」; console.log(this.user); // undefined console.log(this); // window } window.demo(); // 能夠發現和上面的代碼結果同樣
var obj = { user:」前端食堂」, fn:function(){ console.log(this.user); // 前端食堂 } } obj.fn(); // 這裏的this指向對象obj // 注意看最後一行調用函數的代碼 // obj.fn(); // 重要的事情說兩遍!! // this的指向在函數建立時是決定不了的 // 在調用的時候才能夠決定,誰調用就指向誰 // this的指向在函數建立時是決定不了的 // 在調用的時候才能夠決定,誰調用就指向誰
// 其實以上兩點說的還不夠準確,咱們接着往下看 var obj = { user:」前端食堂」, fn:function(){ console.log(this.user); // 前端食堂 } } window.obj.fn(); // 這段代碼跟上面的代碼幾乎是同樣的 // 可是這裏爲何沒有指向window呢? // 按你上面說的不是window調用的方法嗎? // 你們先停下來打個debugger思考一下爲何 // 想不明白不要緊咱們帶着疑問來看下段代碼 var obj = { a:1, b:{ a:2, fn:function(){ console.log(this.a); // 2 } } } obj.b.fn(); // 這裏執行的時候一樣是對象obj經過點語法進行的執行 // 可是this一樣沒有指向window,這是爲何呢? // 好,咱們有幾種狀況須要記住: // 1.若是一個函數中有this // 可是它沒有被上一級的對象所調用 // 那麼this就會指向window(非嚴格模式下) // 2.若是一個函數中有this // 這個函數又被上一級的對象所調用 // 那麼this就會指向上一級的對象 // 3.若是一個函數中有this // 這個函數中包含多個對象 // 儘管這個函數是被最外層的對象所調用 // this卻會指向它的上一級對象 var obj = { a:1; b:{ // a:2, fn:function(){ console.log(this.a); // undefined } } } obj.b.fn(); // 咱們能夠看到,對象b中沒有屬性a,這個this指向 // 的也是對象b,由於this只會指向它的上一級對象 // 無論這個對象中有沒有this要的東西 // 咱們再來看一種狀況 var obj = { a:1, b:{ a:2, fn:function(){ console.log(this.a); // undefined console.log(this); // window } } } var demo = obj.b.fn; demo(); // 在上面的代碼中,this指向的是window // 大家可能會以爲很奇怪 // 實際上是這樣的,有一句話很關鍵,再次敲黑板 // this永遠指向的都是最後調用它的對象 // 也就是看它執行的時候是誰調用的 // 上面的例子中雖然函數fn是被對象b所引用了 // 可是在將fn賦值給變量demo的時候並無執行 // 因此最終this指向的是window
function returnThis(){ return this; } var user = {name:"前端食堂"}; returnThis(); // window returnThis.call(user); // 前端食堂 returnThis.apply(user) ; // 前端食堂 // 這裏就是Object.prototype.call // 和Object.prototype.apply方法 // 他們能夠經過參數來指定this
function returnThis(){ return this; } var user1 = {name:"前端食堂"}; var user1returnThis = returnThis.bind(user1); user1returnThis(); // 前端食堂 var user2 = {name:"前端小食堂"}; user1returnThis.call(user2); // still 前端食堂 // Object.prototype.bind經過一個新函數來提供了永久的綁定 // 並且會覆蓋call和apply的指向
function Fn(){ this.user = "前端食堂"; } var demo = new Fn(); console.log(demo.user); // 前端食堂 // 這裏new關鍵字改變了this的指向 // new關鍵字建立了一個對象實例 // 因此能夠經過對象demo點語法點出函數Fn裏面的user // 這個this指向對象demo // 注意:這裏new會覆蓋bind的綁定 function demo(){ console.log(this); } demo(); // window new demo(); // demo var user1 = {name:"前端食堂"}; demo.call(user1); // 前端食堂 var user2 = demo.bind(user1); user2(); // 前端食堂 new user2(); // demo
// 當this趕上return時 function fn(){ this.user = "前端食堂"; return{}; } var a = new fn; console.log(a.user); // undefined function fn(){ this.user = "前端食堂"; return function(){}; } var a = new fn; console.log(a.user); // undefined function fn(){ this.user = "前端食堂"; return 1; } var a = new fn; console.log(a.user); // 前端食堂 function fn(){ this.user = "前端食堂"; return undefined; } var a = new fn; console.log(a.user); // 前端食堂 // 總結:若是返回值是一個對象 // 那麼this指向就是返回的對象 // 若是返回值不是一個對象 // 那麼this仍是指向函數的實例 // null比較特殊,雖然它是對象 // 可是這裏this仍是指向那個函數的實例 function fn(){ this.user = "前端食堂"; return null; } var a = new fn; console.log(a.user); // 前端食堂
// 最後咱們介紹一種在ES6中的箭頭函數 // 這個箭頭函數中的this被加里奧的英雄登場錘的不行 // 皮不起來了 // 並且,在代碼運行前就已經被肯定了下來 // 誰也不能把它覆蓋 // 這樣是爲了方便讓回調函數中this使用當前的做用域 // 讓this指針更加的清晰 // 因此對於箭頭函數中的this指向 // 咱們只要看它建立的位置便可 function callback(qdx){ qdx(); } callback(()=>{console.log(this)}); // window var user = { name:"前端食堂", callback:callback, callback1(){ callback(()=>{console.log(this)}); } } user.callback(()=>{console.log(this)}); // still window user.callback1(()=>{console.log(this)}); // user
怎麼樣?this其實不過如此吧。再皮也要治住他~
歡迎來個人我的公衆號交流,優質原創文章將同步推送。後臺回覆福利,便可領取福利,你懂得~
你的前端食堂,記得按時吃飯。