this做爲JavaScript中一個大難點,不少初學者一開始都理解不了,或者理解不許確之類的。我在看了《javascript高級程序設計》以及一些大佬的博客後,對this有了新的認識,因而寫下來供你們參考。若是該博客有什麼錯誤的地方,請讀者指正。javascript
this的指向在函數定義的時候是肯定不了的,只有函數執行的時候才肯定this到底指向誰,實際上this的最終指向的是最後調用它的對象
java
因而就延伸出了肯定this指向的幾種方法:數組
雖然上面說的並無錯,可是這麼多種狀況,在實際應用中也不必定可以準確的對應上,咱們不如來學一下this的原理,這樣遇到問題也能夠本身分析。bash
在接下來的實例講解中,我將函數分爲 箭頭函數
與非箭頭函數
。在非箭頭函數
中,this是做爲一個隱式的參數傳入,而在箭頭函數
中,this與其餘變量一視同仁,不會被特殊處理。app
function a(){
var name='ming';
var age=13;
console.log(this.name,age);
}
var name='ye';
var age=15;
a(); //輸出的結果是ye 13
複製代碼
咱們來分析一下:函數
a()做爲一個普通的函數,
this
是做爲一個隱式的參數傳入到函數參數中。它完整的寫法應該是window.a.call(window)
;因爲咱們沒有顯式的調用call
來指定this
的指向,那麼JS就會幫咱們完成這一步,讓調用該函數的對象做爲this
。因此this
在這裏指向的是window
; 而函數的參數是在調用時候才肯定的,因此this.name
輸出的是ye;可是對於age,他在函數裏面只是一個普通的變量,加上做用域鏈的查找規則,會使用離他最近的變量。與會這裏的age
會輸出13。學習
var name='outter';
let obj={
name:'jack',
say(){
console.log(this.name)
};
};
(1) obj.say(); //輸出的結果爲'jack'
let c=obj.say
(2) c() //這裏輸出的是outter;
複製代碼
咱們先來看一下第一個輸出結果。 經過對象
obj
來調用say方法
,這段代碼至關於obj.say.call(obj)
。由於不經過call
強行指定this
指向,那麼JS會默認幫咱們把this
指向調用它的對象,因此輸出的結果是jack
。ui
第二個輸出結果咱們來看看上面的內存圖,
變量C
保存的是say
的地址,也就是說咱們調用C的時候,並不通過obj
的影響,那麼這種狀況也是至關於window.c.call(window)
,因此JS默認狀況下會讓this
指向調用它的對象,也就是全局對象window
。this
注意!!!spa
注意!!!
注意!!!
這裏有一個須要注意的地方,當var name='outter'
改成let name='outter'
的時候,狀況卻變了。
let name='outter'
let obj={
name:'jack',
say(){
console.log(this.name)
}
}
let c=obj.say
c() //輸出的結果是undefined
複製代碼
這是由於let
聲明的變量並無成爲window
的變量,而var
聲明的變量成爲了window
的變量,因此this指向的對象window
並無name
這個屬性
var obj1={
name:'pony',
say(num=''){
console.log(this.name+num)
}
}
var obj2={
name:'jack'
}
(1) obj1.say() //輸出pony
(2) obj1.say.call(obj2,2) //輸出jack2
(3) obj1.say.apply(obj2,[2]) //輸出jack2
複製代碼
call
與apply
的最大區別就是apply
傳入參數須要放在一個數組裏面。 這裏經過call
顯式的指定this
的指向,因而這裏就把obj2
做爲say
的調用對象了。那麼你可能會有疑問,爲何個人say
寫在obj1
裏面,用call
就能夠改變指向呢。這個只是剛好say
寫在了obj1
裏面而已。
var name='one'
let a=function f1(){
console.log(this.name)
}
function f1(){
var name='inner'
a()
}
f1() //輸出的結果爲one,而不是inner
複製代碼
箭頭函數不綁定this,他會捕捉定義的位置或者做用域鏈上最近的this,做爲本身的this。因此 call() / apply() / bind() 方法對於箭頭函數來講只是傳入參數,對它的 this 毫無影響。
注意,{}並不會造成一個做用域,在JS中只有全局做用域與函數生成的局部做用域。
var i=10;
var a={
i:20,
b:()=>{
console.log(this.i)
},
c:function(){
console.log(this.i)
}
}
a.b() //輸出10
a.b.call(a) //輸出10
a.c() //輸出20
複製代碼
由於
{}
並不會造成做用域,箭頭函數沿着做用域鏈向上查找,在全局做用域找到了i
,因而返回全局做用域的i
,因爲箭頭函數並無綁定this
,因此使用call
指定也是沒有辦法改變this
,由於它壓根沒有this
。而對於a.c(),做爲非箭頭函數,上面的例子已經解析了。
var i=10
function f1(){
i=12;
var f=()=>{
console.log(this.i)
}
f()
}
f1() //輸出12
複製代碼
由於函數會造成局部做用域,箭頭函數查找的時候,在
f1
的做用域就能找到i
了。
以上爲我的學習整理的內容,所有的例子都是通過我的檢驗的,歡迎一塊兒交流學習。