走心大白話JavaScript教程(一)理解JS中this指向的小技巧

Terry豆發表於2017-04-27

JS大法好,JS在手,天下我有,信JS,得永生。

這個系列的教程我一開始是寫在github上的,
但是覺得放到掘金來可以讓更多需要的人看到,
就搬到掘金專欄上啦,
如果覺得本教程對你有幫助,請點這裡去github上給我一顆Star~
教程目錄也在github上哈~

本著對技術負責的態度,任何糾正/疑問,儘管提出,我會及時修正/回答。

一定要把每個例子程式碼都拷貝到你的執行環境中邊看結果邊理解,不然學習效果減半,或者沒效果。

閒話說太多了~下面開始第一篇:

理解JS中this指向的小技巧

在看他人寫的js檔案時,會看到許多this,
對this不熟悉的人很容易蒙圈,這裡就說明如何用最簡單的方法去找this指向誰。

切記!這裡說的找“點”大法中的“.”,都是在呼叫的語句裡找,本教程的全域性物件為window!


1、找“點”大法:你找不到“.”的函式呼叫,this指向一般是window:

宣告
function foo(){
  console.log(this)
}複製程式碼
呼叫
foo();    //自己去執行程式碼看this指向誰
//腦補:
window.foo();   //自己去執行程式碼看this指向誰複製程式碼
解讀
不用懷疑,也不用猶豫,找不到任何“.”,this指向window。
以後見到直接呼叫的foo,自動腦補成window.foo(),因為在這種情況下,這兩種寫法是一樣的。複製程式碼
㈠當函式/匿名函式作為引數時,你是找不到“.”的,這種情況下,函式內部的this指向window。
宣告&呼叫
function foo(callback){
    callback(); //呼叫其實在這裡,你是找不到“.”的
}
foo(function(){
    console.log(this);  //自己去執行程式碼看this指向誰
})複製程式碼
解讀
這個例子就是,匿名函式內部列印了this,它作為引數,內部的this指向window複製程式碼


2、找“點”大法:有“.”的函式呼叫,this指向一般是最後一個“.”左側的那個物件:

2-1、呼叫語句裡只能找到一個“.”:
宣告
var bar = {name:'我是bar'};
bar.foo = function(){
  console.log(this)
};複製程式碼
呼叫
bar.foo();  //自己去執行程式碼看this指向誰複製程式碼
解讀
這個例子,我們找到了“.”的存在,“.”左側是bar,指向是bar。複製程式碼
2-2、呼叫語句裡能找到多個“.”:
宣告
var obj = {name:'我是obj'};
obj.bar = {name:'我是bar'};
obj.bar.foo = function(){
  console.log(this)
};複製程式碼
呼叫
obj.bar.foo();  //自己去執行程式碼看this指向誰複製程式碼
解讀
這個例子,我們找到了倆“.”,最後一個“.”左側的物件是bar,那麼this指向就是bar。複製程式碼
㈡如果發現你找到的“.”左側是prototype,那麼再往左找一個“.”,這個“.”左側的物件是this指向。原理在不得不提的原型/原型鏈中給出。


3、物件導向中的this:

對物件導向不夠了解的同學,請儘量讀懂不得不提的原型/原型鏈

閱讀本文,就先專注於找this指向吧!

宣告
function Foo(){
    this.name = 'hahaha'
    console.log(this);
}
Foo.prototype.bar = function(){
    console.log(this);
}
Foo.prototype.funcWithParam = function(fn){
    fn();
}複製程式碼
呼叫
Foo();  //自己去執行程式碼看this指向誰

Foo.prototype.bar();  //自己去執行程式碼看this指向誰

var foo = new Foo(); //自己去執行程式碼看this指向誰

foo.name = '我是foo';

foo.bar(); //自己去執行程式碼看this指向誰

foo.funcWithParam(function(){
    console.log(this);  //自己去執行程式碼看this指向誰
});複製程式碼
解讀
當Foo()時,Foo被當做[普通函式],那麼遵循找“點”大法,Foo內部的this是指向window的;

當Foo.prototype.bar()時,Foo還是被當做[普通函式],遵循找“點”大法,按照2-2,發現找到了prototype,轉而遵循㈡,再向左找,發現this指向Foo;

當new Foo()時,Foo作為[建構函式]被例項化,Foo內部的this指向例項化後的Foo,也就是我宣告的foo;

當foo.bar時,遵循找“點”大法,按照2-1,發現this指向foo;

當foo.funcWithParam(匿名函式)時,匿名函式前沒有“.”,匿名函式作為引數,所以遵循㈠,發現其內部this指向window複製程式碼


4、call和apply會改變this指向,在巧妙理解call、apply單獨詳解。


小結:

  • 找不到“.”的函式呼叫,其內部的this一般指向window象;
  • 找得到“.”的函式呼叫,其內部的this一般指向最後一個“.”左側的那個物件,如果左側是prototype,再向左找一個;
  • 明確區分函式是[建構函式]還是[普通函式],[建構函式]內的this指向例項化後的物件;
  • 函式作為引數傳遞,被呼叫時其內部的this一般指向window。
  • call和apply會改變this指向,參閱巧妙理解call、apply
  • ES6/7的箭頭函式也會影響this指向,這個很簡單,我就不多講啦~

一句話來說,就是“誰調的我(普通函式),我內部的this就指向誰;new我一下(建構函式),我內部的this就指向我的例項化”

PS:
歡迎轉載,需要註明原址。
教程之間緊密聯絡,不懂的地方,請好好看下全系列教程目錄
有沒有你不懂的那個關鍵字在裡面。
如果幫到你,別忘了給我一顆Star~

相關文章