深刻JavaScript系列02--this關鍵字

「You know nothing Jon Snow」web

this關鍵字

「你不知道的JavaScript學習筆記02」app

概念

  • 定義:當一個函數被調用時,會建立一個執行上下文。這個執行上下文會包含函數在哪裏被調用(調用棧)、函數的調用方式、傳入的參數等信息。this就是這個記錄的一個屬性,會在函數執行的過程當中用到
  • 因此能夠明確一點:this既不指向函數自身也不指向函數的詞法做用域,this指代的是當前函數被調用時的執行上下文
  • this其實是在函數被調用時發生的綁定,它指向什麼徹底取決於函數在哪裏被調用

綁定規則

默認綁定

  • 獨立函數調用,this默認綁定全局對象(在嚴格模式下默認綁定不會指定上下文對象)
function foo() {
 console.log(this.a)  }  var a = "fuck";  foo();//fuck 複製代碼

隱式綁定

  • 當函數做爲對象的屬性被調用時,會觸發隱式綁定
var obj1 = {
 a:1,  foo:function() {  console.log(this.a);  }  }  var obj2 = {  b:2,  bar:function() {  consolelog(this.b);  }  }   obj1.foo();//1  obj2.bar();//2 複製代碼
  • 當函數引用有上下文對象時,隱式綁定規則會把函數調用中的this綁定到這個上下文對象。
  • 注意:對象屬性引用鏈中只有上一層或者說最後一層在調用位置中起做用。
function foo() {
 console.log(this.a);  }   var obj1 = {  a:1,  foo:foo  }   var obj2 = {  a:2,  obj1  }   var obj3 = {  a:3,  obj2  }   obj3.obj2.obj1.foo(); //1; 複製代碼

隱式丟失

var obj1 = {
 a:1,  foo:function() {  console.log(this.a);  }  }  var a = "shit";   var bar = obj1.foo;  bar(); //shit  複製代碼

在js中,函數屬於Object的之類,在這塊代碼塊中的RHS其實是傳遞函數的引用,而this是由調用宿主和執行上下文決定的,函數執行時執行的是默認綁定的規則編輯器

顯式綁定

  • 概念:直接指定函數執行時的上下文對象
  • 內置函數(對象)Function上的三個方法:call()、apply()、bind()
var obj1 = {
 a:1  }  function foo() {  console.log(this.a);  }  var a = 2;  foo.call(obj1); // 1  foo.apply(obj1); //1  var bar = foo.bind(obj1);  bar(); //1 複製代碼

new聲明綁定

  • new關鍵字函數

    avaScript中的「構造函數」有別於其餘語言,在JavaScript中,在函數調用前用new關鍵字進行聲明,該函數就成了「構造函數」,函數自己並沒有區別。 使用new來調用函數,或者說發生構造函數調用時,會自動執行下面的操做。1.建立(或者說構造)一個全新的對象。2.這個新對象會被執行[[Prototype]]鏈接。3.這個新對象會綁定到函數調用的this。4.若是函數沒有返回其餘對象,那麼new表達式中的函數調用會自動返回這個新對象。學習

//eg
function myNew() {   // 第一個參數是構造函數  var Constructor = [].shift.call(arguments);   // 建立一個繼承對象  var obj = Object.create(Constructor.prototype);   // 執行構造函數,this執行obj  var result = Constructor.apply(obj, arguments);   // 構造函數返回是對象,優先使用返回的對象,不然是obj  return result instanceof Object ? result : obj;   // 執行構造函數,this執行obj  var result = Constructor.apply(obj, arguments);   // 構造函數返回是對象,優先使用返回的對象,不然是obj  return result instanceof Object ? result : obj; }  var a = 'fuck';  function foo(a) {  this.a = a;  this.saya = function() {  console.log(this.a)  } } var b = "shit"; var obj = myNew(foo,b); // new foo(b) obj.saya; //shit; 複製代碼

使用new來調用foo(..)時,咱們會構造一個新對象並把它綁定到foo(..)調用中的this上。new是最後一種能夠影響函數調用時this綁定行爲的方法,咱們稱之爲new綁定。ui

優先級

new綁定 > 顯式綁定 >隱式綁定 >默認綁定this

能夠按照下面的順序來進行判斷:url

1.函數是否在new中調用(new綁定)?spa

若是是的話this綁定的是新建立的對象。prototype

var obj = new foo(); //綁定obj
複製代碼

2.函數是否經過call、apply(顯式綁定)或者硬綁定調用?

若是是的話,this綁定的是指定的對象。

var bar = new foo.call(obj); //綁定obj
複製代碼

3.函數是否在某個上下文對象中調用(隱式綁定)?

若是是的話,this綁定的是那個上下文對象。

var bar = obj.foo(); //綁定obj
複製代碼

4.若是都不是的話,使用默認綁定。若是在嚴格模式下,就綁定到undefined,不然綁定到全局對象。

this
this

箭頭函數

箭頭函數並非使用function關鍵字定義的,而是使用被稱爲「胖箭頭」的操做符=>定義的。箭頭函數不使用this的四種標準規則,而是根據外層(函數或者全局)做用域來決定this。

function foo() {
 return (a) => {  console.log(this.a)  } } var obj1 = {  a:1 } var obj2 = {  a:2 }  var bar = foo.call(obj1); bar.call(obj2); //1,不是2 複製代碼

foo內部的箭頭函數會捕獲調用foo時的this;箭頭函數的this查詢規則聽從詞法;外層函數綁定的this會間接傳遞給內部的箭頭函數,箭頭函數的綁定沒法被修改。

function foo() {
 var _this = this;  setTimeout(function(){  console.log(_this.a)  },100) } function bar() {  setTimeout(()=>{  console.log(this.a)  },100) } function baz() {  setTimeout(function(){  console.log(this.a)  },100) } var obj = {  a: 1 } var a = 2; foo.call(obj); //1 bar.call(obj); //1 baz.call(obj); //2, 天惹,回調函數的this執行了默認綁定  複製代碼

參考文獻: 《你不知道的JavaScript(上卷)》

本文使用 mdnice 排版

相關文章
相關標籤/搜索