1. 程式人生 > 程式設計 >javascript this指向相關問題及改變方法

javascript this指向相關問題及改變方法

在學習javascript中我們往往會被this的指向問題弄的頭昏轉向,今天我們就來學習一下this的指向問題,和改變this指向的方法。

一.this的指向問題

在學習this的指向問題之前我們需要明白兩點:

1:this永遠指向一個物件;

2:this的指向完全取決於函式呼叫的位置;

針對上面第一點我們能很好理解,因為在javascript中一切都是物件。第二點其實也是好理解,當函式呼叫的位置不同是,this的指向的物件就不同,所以可以說this的指向可以動態變換的,下面我們先通過一個簡單的例子來看一下this的指向是變換的

<script>
function fun(){
   console.log(this.name);

 }
 var change={
   name:'hello',f:fun
 }
 var name ='world'
 var result=change.f()//hello
 fun();//world
</script>

通過上述例子我們可以很清楚的看到this的指向的變化,因為有一個函式在物件change裡面,所以this就是指向的函式外部的物件,所以輸出了hello。

想必看完上述例子後大家對this的動態指向切換有了一定的瞭解。

那麼接下來,我們對this使用最頻繁的幾種情況做一個總結,最常見的基本就是以下3種:

物件中的方法,事件繫結 ,建構函式 ,定時器

前兩個就不必多說了,我們看一下定時器中的this指向問題,

var obj = {
  fun:function(){
    this ;
  }
}
​
setInterval(obj.fun,1000);   // this指向window物件
setInterval('obj.fun()',1000); // this指向obj物件

setInterval() 是window物件下內建的一個方法,接受兩個引數,第一個引數允許是一個函式或者是一段可執行的 JS 程式碼,第二個引數則是執行前面函式或者程式碼的時間間隔;

在上面的程式碼中,setInterval(obj.fun,1000) 的第一個引數是obj物件的fun ,因為 JS 中函式可以被當做值來做引用傳遞,實際就是將這個函式的地址當做引數傳遞給了 setInterval 方法,換句話說就是 setInterval 的第一引數接受了一個函式,那麼此時1000毫秒後,函式的執行就已經是在window物件下了,也就是函式的呼叫者已經變成了window物件,所以其中的this則指向的全域性window物件;

而在 setInterval('obj.fun()',1000) 中的第一個引數,實際則是傳入的一段可執行的 JS 程式碼;1000毫秒後當 JS 引擎來執行這段程式碼時,則是通過 obj 物件來找到 fun 函式並呼叫執行,那麼函式的執行環境依然在 物件 obj 內,所以函式內部的this也就指向了 obj 物件;

除了這些我們還需要理解三個可以改變this指向的函式,包括箭頭函式,call(),apply()

箭頭函式:官方有解釋,箭頭函式引入的其中一個原因,就是其不繫結this;在箭頭函式中,箭頭函式的this被設定為封閉的詞法環境的,換句話說,箭頭函式中的this取決於該函式被建立時的環境。

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
// 接著上面的程式碼
// 作為物件的一個方法呼叫
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

// 嘗試使用call來設定this
console.log(foo.call(obj) === globalObject); // true

// 嘗試使用bind來設定this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true

無論如何,foo 的 this 被設定為他被建立時的環境(在上面的例子中,就是全域性物件)。這同樣適用於在其他函式內建立的箭頭函式:這些箭頭函式的this被設定為封閉的詞法環境的。

// 建立一個含有bar方法的obj物件,
// bar返回一個函式,
// 這個函式返回this,
// 這個返回的函式是以箭頭函式建立的,
// 所以它的this被永久繫結到了它外層函式的this。
// bar的值可以在呼叫中設定,這反過來又設定了返回函式的值。
var obj = {
 bar: function() {
  var x = (() => this);
  return x;
 }
};

// 作為obj物件的一個方法來呼叫bar,把它的this繫結到obj。
// 將返回的函式的引用賦值給fn。
var fn = obj.bar();

// 直接呼叫fn而不設定this,
// 通常(即不使用箭頭函式的情況)預設為全域性物件
// 若在嚴格模式則為undefined
console.log(fn() === obj); // true

// 但是注意,如果你只是引用obj的方法,
// 而沒有呼叫它
var fn2 = obj.bar;
// 那麼呼叫箭頭函式後,this指向window,因為它從 bar 繼承了this。
console.log(fn2()() == window); // true

call和apply方法:將一個物件作為call或者apply的第一個引數,this將會被繫結到這個引數物件上

var obj = {parent:'男'};
var parent = '28';
function child(obj){
  console.log(this.parent);
}
child(); // 28 
child.call(obj); //男
child.apply(obj); //男

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。