JavaScript基礎心法——this

原文地址:JavaScript基礎心法——thisjavascript

歡迎star。html

若是有錯誤的地方歡迎指正。java


看看這個有着深不可測的魔力的this究竟是個什麼玩意兒 ~git

什麼是this

在傳統面向對象的語言中,好比Java,this關鍵字用來表示當前對象自己,或當前對象的一個實例,經過this關鍵字能夠得到當前對象的屬性和調用方法。es6

在JavaScript中,this彷佛表現地略有不一樣,這也是讓人「討厭」的地方~github

ECMAScript規範中這樣寫:瀏覽器

this 關鍵字執行爲當前執行環境的 ThisBinding。app

MDN上這樣寫:函數

In most cases, the value of this is determined by how a function is called.
在絕大多數狀況下,函數的調用方式決定了this的值。this

能夠這樣理解,在JavaScript中,this的指向是調用時決定的,而不是建立時決定的,這就會致使this的指向會讓人迷惑,簡單來講,this具備運行期綁定的特性。

參考資料:this - JavaScript | MDN

來看看不一樣的狀況五花八門的this吧~

調用位置

首先須要理解調用位置,調用位置就是函數在代碼中被調用的位置,而不是聲明的位置。

經過分析調用棧(到達當前執行位置所調用的全部函數)能夠找到調用位置。

function baz(){
  console.log("baz");
  bar();
}
function bar(){
  console.log("bar");
  foo();
}
function foo(){
  console.log("foo");
}
baz();

當咱們調用baz()時,它會以此調用baz()bar()foo()

對於foo():調用位置是在bar()中。
對於bar():調用位置是在baz()中。
而對於baz():調用位置是全局做用域中。

能夠看出,調用位置應該是當前正在執行的函數的前一個調用中。

全局上下文

在全局執行上下文中this都指代全局對象。

  • this等價於window對象
  • var === this. === winodw.
console.log(window === this); // true
var a = 1;
this.b = 2;
window.c = 3;
console.log(a + b + c); // 6

在瀏覽器裏面this等價於window對象,若是你聲明一些全局變量,這些變量都會做爲this的屬性。

函數上下文

在函數內部,this的值取決於函數被調用的方式。

直接調用

this指向全局變量。

function foo(){
  return this;
}
console.log(foo() === window); // true

call()、apply()

this指向綁定的對象上。

var person = {
  name: "axuebin",
  age: 25
};
function say(job){
  console.log(this.name+":"+this.age+" "+job);
}
say.call(person,"FE"); // axuebin:25
say.apply(person,["FE"]); // axuebin:25

能夠看到,定義了一個say函數是用來輸出nameagejob,其中自己沒有nameage屬性,咱們將這個函數綁定到person這個對象上,輸出了本屬於person的屬性,說明此時this是指向對象person的。

若是傳入一個原始值(字符串、布爾或數字類型)來當作this的綁定對象, 這個原始值會被轉換成它的對象形式(new String()),這一般被稱爲「裝箱」。

callapplythis的綁定角度上來講是同樣的,惟一不一樣的是它們的第二個參數。

bind()

this將永久地被綁定到了bind的第一個參數。

bindcallapply有些類似。

var person = {
  name: "axuebin",
  age: 25
};
function say(){
  console.log(this.name+":"+this.age);
}
var f = say.bind(person);
console.log(f());

箭頭函數

全部的箭頭函數都沒有本身的this,都指向外層。

關於箭頭函數的爭論一直都在,能夠看看下面的幾個連接:

ES6 箭頭函數中的 this?你可能想多了(翻譯)

關於箭頭函數this的理解幾乎徹底是錯誤的 #150

MDN中對於箭頭函數這一部分是這樣描述的:

An arrow function does not create its own this, the this value of the enclosing execution context is used.
箭頭函數會捕獲其所在上下文的this值,做爲本身的this值。

function Person(name){
  this.name = name;
  this.say = () => {
    var name = "xb";
    return this.name;
  }
}
var person = new Person("axuebin");
console.log(person.say()); // axuebin

箭頭函數經常使用語回調函數中,例如定時器中:

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

附上MDN關於箭頭函數this的解釋:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions#不綁定_this

做爲對象的一個方法

this指向調用函數的對象。

var person = {
  name: "axuebin",
  getName: function(){
    return this.name;
  }
}
console.log(person.getName()); // axuebin

這裏有一個須要注意的地方。。。

var name = "xb";
var person = {
  name: "axuebin",
  getName: function(){
    return this.name;
  }
}
var getName = person.getName;
console.log(getName()); // xb

發現this又指向全局變量了,這是爲何呢?

仍是那句話,this的指向得看函數調用時。

做爲一個構造函數

this被綁定到正在構造的新對象。

經過構造函數建立一個對象其實執行這樣幾個步驟:

  1. 建立新對象
  2. 將this指向這個對象
  3. 給對象賦值(屬性、方法)
  4. 返回this

因此this就是指向建立的這個對象上。

function Person(name){
  this.name = name;
  this.age = 25;
  this.say = function(){
    console.log(this.name + ":" + this.age);
  }
}
var person = new Person("axuebin");
console.log(person.name); // axuebin
person.say(); // axuebin:25

做爲一個DOM事件處理函數

this指向觸發事件的元素,也就是始事件處理程序所綁定到的DOM節點。

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

HTML標籤內聯事件處理函數

this指向所在的DOM元素

<button onclick="console.log(this);">Click Me</button>

jQuery的this

在許多狀況下JQuery的this都指向DOM元素節點。

$(".btn").on("click",function(){
  console.log(this); 
});

總結

若是要判斷一個函數的this綁定,就須要找到這個函數的直接調用位置。而後能夠順序按照下面四條規則來判斷this的綁定對象:

  1. new調用:綁定到新建立的對象
  2. callapplybind調用:綁定到指定的對象
  3. 由上下文對象調用:綁定到上下文對象
  4. 默認:全局對象

注意:箭頭函數不使用上面的綁定規則,根據外層做用域來決定this,繼承外層函數調用的this綁定。

相關文章
相關標籤/搜索