觀感度:🌟🌟🌟🌟🌟javascript
口味:清爽綠豆前端
烹飪時間:15minjava
你皮任你皮,我當你瓜皮。node
衆所周知,this
在JavaScript中的指向一直很難讓人理解,想要學好JavaScript,this
也是咱們必需要搞清楚的。其實,this
並無那麼難,本文將力爭帶你治療this
的「皮」。瀏覽器
首先,來科普三個問題!app
this
是聲明函數時附加的參數,指向特定的對象,也就是隱藏參數。函數
好比LOL中各類隱藏的彩蛋,當水晶先鋒斯卡納在草叢裏停留超過15秒不動,會模仿寵物小精靈。ui
「皮卡!皮卡!皮卡丘!」this
「斯卡!斯卡!斯卡納!」spa
好,相信你們已經理解什麼是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其實不過如此吧。再皮也要治住他~
歡迎來個人我的公衆號交流,優質原創文章將同步推送。後臺回覆福利,便可領取福利,你懂得~
你的前端食堂,記得按時吃飯。