JavaScript基礎二:理解執行棧與This指向

哪裏調用this就指向哪裏。this指向依賴於調用時的位置和調用方法,而非建立時的位置。

全局上下文

默認狀況下,全局上下文環境的this指向於window對象。git

var a = 1;
 console.log(this.a);     // 1 
 console.log(this == window);   // true

值得注意的是,在ES6中let關鍵字聲明定義的全局變量,不掛在頂層對象window中github

let a = 1;
 console.log(this.a);   // undefined
 console.log(this == window);  // true

函數上下文

在分析函數上下文以前,咱們先來了解下調用位置。JavaScript引擎在執行代碼時按照順序執行,則全局上下文(global text)應當首先進入調用棧。以後纔是函數上下文進棧,當函數被調用時則進行出棧。數組

舉個例子app

function foo(){
    foo2();
  }
  function foo2(){
    foo3();
  }
  function foo3(){
    console.log("i am foo3");
  }
  foo();

如上這段代碼,最開始是全局上下文首先入棧,然後foo入棧,看到foo中還調用foo2則繼續進棧,同理入棧foo3。根據棧後進先出的原則,則foo3首先被彈出棧,然後foo二、foo依次出棧。該函數上下文所在棧元素的前一個元素,則爲調用位置。而實際上,須要結合調用方式來斷定。函數

var a  = 1;
function foo(){
  var a = 2;
  foo2();
}
function foo2(){
  var a = 3;  
  console.log(this.a);    // 1
  foo3();
}
function foo3(){
  console.log(this.a);  // 1
  console.log("i am foo3");
}
foo();

此處爲函數獨立調用,因此this實際指向於windowthis

普通函數調用

在非嚴格模式下,普通函數的this指向於windowcode

var a = 1;
  function foo(){
   console.log(this.a);
  }

而在嚴格模式下,普通函數的this是undefined對象

'use strict'
 var a  = 1;
 function foo(){
  console.log(this);  // undefined
  console.log(this.a);  // 報錯
 }
 foo();

嵌套函數調用事件

var a  = 1;
  function foo(){
   return function(){
    var a = 2;
    console.log(this.a);
   }
  }
  foo()();   // 1
  
  var f = foo(); 
  f();   // 1

對象中的函數調用

在一個函數上下文中,this由調用者提供,由調用函數的方式來決定。若是調用者函數,被某一個對象所擁有,那麼該函數在調用時,內部的this指向該對象。ip

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

若是函數獨立調用,那麼該函數內部的this,則指向undefined。可是在非嚴格模式中,當this指向undefined時,它會被自動指向全局對象。

var a  = 1;
 function getA(){
  return this.a;
 }
 var obj  = {
   a:2,
   foo:getA
 };
 var f = obj.foo;
 console.log(f());   // 1

須要注意的是,這僅是針對函數上下文而言。

var a  = 1;
 function getA(){
  return this.a;
 }
 var obj = {
  a:2,
  b:this.a,
  foo:function(){
    return this.a;
  }
 };
 console.log(obj.b);  // 1
 console.log(obj.foo());  // 2

call/apply調用

使用call/apply調用時,this做用域指向call/apply的第一個參數對象。call/apply自己差異不大,主要差異就是call傳遞的形參是一個一個的,而apply是一整個數組傳。

var song = 'hello';
 function sing(){
   console.log(this.song);
 }
 var obj  = {
   song:'let it go'
 };
 sing.call(obj);  // let it go

構造函數調用

this指向被建立的對象

var age = 13;
 function Animal(age){
   this.age = age;
 }  
 var dog = new Animal(12);
 console.log(dog.age);   //12

DOM事件處理函數調用

this指向於觸發事件的DOM元素

var ele = document.getElementById("id");
ele.addEventListener("click",function(e){
 console.log(this);
 console.log(this === e.target); // true
})

箭頭函數調用

箭頭函數調用應當是this指向在函數調用裏面的特例了,在箭頭函數中,會捕獲其所在上下文的this值,做爲本身的this值。簡單來講,就是包裹箭頭函數的第一個普通函數中的this。

function foo() {  
  setTimeout(()=>{
   console.log(this.a);
  },100)
}
 var obj = {
 a: 2
}
 foo.call(obj);   // 2

總結

肯定This指向時,首先找到函數調用位置及調用方式

  1. new調用:綁定到新建立的對象
  2. callapplybind調用:綁定到指定的對象
  3. 由上下文對象調用:綁定到上下文對象
  4. 默認:全局對象
參考文章: https://github.com/axuebin/ar...
相關文章
相關標籤/搜索