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

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

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

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

必定要把每一個例子代碼都拷貝到你的運行環境中邊看結果邊理解,否則學習效果減半,或者沒效果。

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

理解JS中this指向的小技巧

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

切記!這裏說的找「點」大法中的「.」,都是在調用的語句裏找,本教程的全局對象爲window!


一、找「點」大法:你找不到「.」的函數調用,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複製代碼


二、找「點」大法:有「.」的函數調用,this指向通常是最後一個「.」左側的那個對象:

2-一、調用語句裏只能找到一個「.」:
聲明
var bar = {name:'我是bar'};
bar.foo = function(){
  console.log(this)
};複製代碼
調用
bar.foo();  //本身去運行代碼看this指向誰複製代碼
解讀
這個例子,咱們找到了「.」的存在,「.」左側是bar,指向是bar。複製代碼
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指向。原理在不得不提的原型/原型鏈中給出。


三、面向對象中的this:

對面向對象不夠了解的同窗,請儘可能讀懂不得不提的原型/原型鏈

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

聲明
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複製代碼


四、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~
app

相關文章
相關標籤/搜索