this的指向問題

問題由來

  var obj = {
    foo: function () { 
      console.log(this.bar) 
    },
    bar: 1
  };
  var foo = obj.foo;
  var bar = 2;
  obj.foo() // 1
  foo() // 2  

雖然obj.foofoo指向同一個函數(shù)裆针,但是執(zhí)行結果可能不一樣功偿。
this指的是函數(shù)運行時所在的環(huán)境,對于obj.foo來說,foo運行在obj環(huán)境堰酿,所以this指向obj;對于foo()來說宵蕉,foo()運行在全局環(huán)境耕赘,所以this指向全局環(huán)境。

函數(shù)的運行環(huán)境到底是怎么決定的贞绳?

內存的數(shù)據(jù)結構

  1. 將對象賦值給變量obj
    var obj = { foo: 5 };
    JavaScript 引擎會先在內存里面谷醉,生成一個對象{ foo: 5 },然后把這個對象的內存地址賦值給變量obj冈闭。
    即變量obj是一個地址俱尼。后面如果要讀取obj.foo,引擎先從obj拿到內存地址萎攒,然后再從該地址讀出原始的對象遇八,返回它的foo屬性矛绘。

    avatar

  2. 將函數(shù)賦值給變量obj
    var obj = { foo: function () {} };
    JavaScript 引擎會將函數(shù)單獨保存在內存中,然后再將函數(shù)的地址賦值給foo屬性的value屬性刃永。

    avatar

由于函數(shù)是一個單獨的值货矮,所以它可以在不同的環(huán)境(上下文)執(zhí)行。

this指向的規(guī)律

  • 在函數(shù)體中揽碘,簡單調用函數(shù)時(非顯示/隱式綁定下)次屠,嚴格模式下 this 綁定到undefined,否則綁定到全局對象 window/global雳刺;
  • 一般由上下文對象調用劫灶,綁定在該對象上;
  • 一般由 bind/call/apply 方法顯示調用掖桦,綁定到指定參數(shù)的對象上本昏;
  • 一般構造函數(shù)new調用,綁定到新創(chuàng)建的對象上枪汪;
  • 箭頭函數(shù)中涌穆,根據(jù)外層上下文綁定的this決定this的指向。

四類場景

  1. "test()"形式
  function f1(){
   console.log(this)  
 }
 var  arr = [f1,2,3];   
 var f2 = arr[0];
 f2();        

<details>
<summary>答案</summary>
<pre>
this指向 window/嚴格模式下undefined
</pre>
</details>
直接不帶任何引用形式去調用函數(shù)雀久,則this會指向全局對象宿稀,因為沒有其他影響去改變this,this默認就是指向全局對象(瀏覽器是window赖捌,Node中是global)的祝沸。這個結論是在非嚴格模式的情況下,嚴格模式下這個this其實是undefined的越庇。

  1. "XXX.test()"形式
  var a = 1
  function test(){
    console.log(this.a)
  }
  var obj = {
    a:2,
    test
  }
  obj.test() 

<details>
<summary>答案</summary>
<pre>
2
</pre>
</details>
一句話罩锐,誰去調用這個函數(shù)的,這個函數(shù)中的this就綁定到誰身上卤唉。

測試題

  var a = 1
  function test(){
    console.log(this.a)
  }
  var obj = {
    a:2,
    test
  }
  var testCopy = obj.test
  testCopy()

<details>
<summary>答案</summary>
<pre><code>
1
</code></pre>
</details>

  var a = 1
  function test(){
    console.log(this.a)
  }
  var obj = {
    a:2,
    test
  }
  var obj0 = {
      a:3,
      obj
  }
  obj0.obj.test()

<details>
<summary>答案</summary>
<pre>
<code>
2
即使是這種串串燒的形式涩惑,結果也是一樣的,test()中的this只對直屬上司(直接調用者obj)負責桑驱。
</code>
</pre>
</details>

  1. "test.call(xxx) / test.apply(xxx) / test.bind()"形式
  var a = 1
  function test(){
    console.log(this.a)
  }
  var obj = {
    a:2,
    test
  }
  var testCopy = obj.test
  testCopy.call(obj)

<details>
<summary>答案</summary>
<pre><code>
2
</code></pre>
</details>
可以看到竭恬,我們通過call/apply來調用testCopy,并且傳入了你想要 this 指向的上下文熬的,那么this就會按照你的指示行事萍聊。

  1. "new test()"形式
  var a = 1
  function test(a){
    this.a = a
  }
  var b = new test(2)
  console.log(b.a)

<details>
<summary>答案</summary>
<pre><code>
2
</code></pre>
</details>
new這個操作符其實是new了一個新對象出來,而被new的test我們稱為構造函數(shù)悦析,我們可以在這個構造函數(shù)里定義一下將要到來的新對象的一些屬性寿桨。那么在構造函數(shù)里,我們怎樣去描述這個還未出生的新對象呢?沒錯亭螟,就是用this挡鞍。所以構造函數(shù)里的this指的就是將要被new出來的新對象。

特別的 箭頭函數(shù)

  var a = 1;
  var test = () => {
    var a = 3;
    console.log(this.a)
  }
  var obj = {
    a: 2,
    test
  }
  obj.test()

<details>
<summary>答案</summary>
<pre><code>
1
</code></pre>
</details>
箭頭函數(shù)中this對象就是定義時所在的作用域预烙,也就是說箭頭函數(shù)本身沒有this墨微,內部的this就是外層代碼塊作用域中的this。

測試題

  var a = 1
  var obj = {
    a: 2,
    test: ()=> {
      console.log(this.a)
    }
  }
  obj.test()  

<details>
<summary>答案</summary>
<pre><code>
1
func在foo調用時定義扁掸,此時的foo所在作用域為obj翘县,因此this指向obj
</code></pre>
</details>

  var a = 1
  function foo(){
    var test = () => {
      console.log(this.a)
    }
    return test
  }
  var obj = {
    a : 2,
    foo:foo
  }
  obj.foo()()  
  

<details>
<summary>答案</summary>
<pre><code>
2
</code></pre>
</details>

隨機測試題

  var b = {
    a: 23,
    c: 3,
    d: {
      a: 78,
      e: {
        a: 100,
        f: function () {
          console.log(this.a);
        }
      }
    }
  }
  var fn = b.d.e.f;
  fn();
  b.d.e.f(); 

<details>
<summary>答案</summary>
<pre><code>
undefined
100
</code></pre>
</details>

  var point = { 
    x : 0, 
    y : 0, 
    moveTo : function(x, y) { 
      this.x = x;
      console.log(this.x); 
      console.log(this);   

      var moveX = function(x) { 
        this.x = x;
      }; 
      var moveY = function(y) { 
        this.y = y;
      } 
      moveX(x); 
      moveY(y); 
    } 
  }; 
  point.moveTo(1, 1); 
  console.log(point.x); 
  console.log(point.y);
  console.log(x); 
  console.log(y);

<details>
<summary>答案</summary>
<pre><code>
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
this.x = x;
console.log(this.x); // 1
console.log(this); // point對象
var moveX = function(x) {
this.x = x;
};
var moveY = function(y) {
this.y = y;
}
moveX(x);
moveY(y);
}
};
point.moveTo(1, 1);
console.log(point.x); // 1
console.log(point.y); // 0
console.log(x); // 1
console.log(y);// 1
</code>

point對象下的moveTo方法中的moveX與moveX方法在調用時都是全局調用,綁定的對象都是window谴分。
</pre>
</details>

  var point = { 
    x : 0, 
    y : 0, 
    moveTo : function(x, y) { 
        var that = this; 
        var moveX = function(x) { 
            that.x = x; 
        }; 
        var moveY = function(y) { 
            that.y = y;
        } 
        moveX(x); 
        moveY(y); 
    } 
  }; 
  point.moveTo(1, 1); 
  console.log(point.x); 
  console.log(point.y); 
  console.log(x) 
  console.log(y) 

<details>
<summary>答案</summary>
<pre><code>
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
var that = this; //內部變量替換
// 內部函數(shù)
var moveX = function(x) {
that.x = x;
};
// 內部函數(shù)
var moveY = function(y) {
that.y = y;
}
moveX(x); //這里依然是全局調用锈麸,但是在給變量賦值時,不再是this指向牺蹄,而是that指向忘伞,而that指向的對象是 point。
moveY(y);
}
};
point.moveTo(1, 1);
console.log(point.x); // 1
console.log(point.y); // 1
console.log(x) // 報錯 x is not defined
console.log(y) //
</code></pre>
</details>

const obj = {
  name: " jsCoder",
  skill: ["es6", "react", "angular"],
  say: function() {
    for (var i = 0, len = this.skill.length; i < len; i++) {
      setTimeout(function() {
        console.log("No." + i + this.name);
        console.log(this.skill[i]);
        console.log("--------------");
      }, 0);
      console.log(i);
    }
  }
};
obj.say();

參考地址

不要再問我this的指向問題了_個人文章 - SegmentFault 思否
JavaScript 的 this 原理 - 阮一峰的網(wǎng)絡日志

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末沙兰,一起剝皮案震驚了整個濱河市氓奈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鼎天,老刑警劉巖舀奶,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異斋射,居然都是意外死亡育勺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門绩鸣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怀大,“玉大人纱兑,你說我怎么就攤上這事呀闻。” “怎么了潜慎?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵捡多,是天一觀的道長。 經(jīng)常有香客問我铐炫,道長垒手,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任倒信,我火速辦了婚禮科贬,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己榜掌,他們只是感情好优妙,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著憎账,像睡著了一般套硼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上胞皱,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天邪意,我揣著相機與錄音,去河邊找鬼反砌。 笑死雾鬼,一個胖子當著我的面吹牛,可吹牛的內容都是我干的于颖。 我是一名探鬼主播呆贿,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼森渐!你這毒婦竟也來了做入?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤同衣,失蹤者是張志新(化名)和其女友劉穎竟块,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耐齐,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡浪秘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了埠况。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耸携。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖辕翰,靈堂內的尸體忽然破棺而出夺衍,到底是詐尸還是另有隱情,我是刑警寧澤喜命,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布沟沙,位于F島的核電站,受9級特大地震影響壁榕,放射性物質發(fā)生泄漏矛紫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一牌里、第九天 我趴在偏房一處隱蔽的房頂上張望颊咬。 院中可真熱鬧,春花似錦、人聲如沸喳篇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杭隙。三九已至哟绊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間痰憎,已是汗流浹背票髓。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留铣耘,地道東北人洽沟。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像蜗细,于是被迫代替她去往敵國和親裆操。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內容

  • 1. this指向問題 1.1 認識詞法作用域 其實我們js中的作用域就是詞法作用域,我們會發(fā)現(xiàn)詞法作用域最重要的...
    時光如劍閱讀 956評論 0 8
  • 最近有點閑暇時間炉媒,就來總結js中this的指向問題踪区,如有不對,請指出吊骤。this指向缎岗,網(wǎng)上做多的描述是指向那個最終調...
    AlisaMfz閱讀 564評論 0 0
  • 要徹底理解JS中的this指向問題,建議多結合一些相關的面試題,理解記憶,不必硬背 關于this問題:只需記住誰調...
    追馬的時間種草閱讀 156評論 0 0
  • 一:this 是在函數(shù)被調用時確定的,它的指向完全取決于函數(shù)調用的地方白粉,而不是它被聲明的地方(除箭頭函數(shù)外)传泊。當一...
    張艷華_zzz閱讀 251評論 0 0
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友鸭巴。感恩相遇眷细!感恩不離不棄。 中午開了第一次的黨會鹃祖,身份的轉變要...
    迷月閃星情閱讀 10,559評論 0 11