理解this作用域
《javascript高級程序設計》中有說到:
this對象是在運行時基於函數的執行環境綁定的:在全局函數中,this等於window,而當函數被作爲某個對象調用時,this等於那個對象。不過,匿名函數具有全局性,因此this對象同常指向window
針對於匿名函數this具有全局性的觀點仍是有爭議的,可參考 https://www.zhihu.com/questio...
關於閉包經常會看到這麼一道題:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
console.log(object.getNameFunc()());//result:The Window
<font color="green">在這裏,getNameFunc return了1個匿名函數,可能你會認爲這就是輸出值爲<font color="blue">The Window</font>的原因 </font>
但是,我們再來嘗試寫1個匿名函數
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return this.funAA;
},
funAA:function(){
return this.name
}
};
console.log(object.getNameFunc()(),object.funAA())
可以發現,同樣是匿名函數,卻輸出了<font color="blue">The Window, My Object</font>
在作用域鏈中,執行函數時會創建一個稱爲“運行期上下文(execution context)”的內部對象,運行期上下文定義了函數執行時的環境。個人認爲是因爲<font color="red">函數執行在window作用域</font>下,getNameFunc的作用域鏈被初始化爲<font color="red">window的[[Scope]]</font>所包含的對象,導致輸出結果爲window.name
對作用域鏈不是很瞭解的同學,可以查看這邊文章【Javascript】深入理解javascript作用域與作用域鏈
實踐是檢驗真理的唯一標準,讓我們用代碼測試一下
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return this.funAA();
},
funAA:function(){
return this.name
}
};
console.log(object.getNameFunc(),object.funAA())
可以發現,輸出了 <font color="blue">My Object, My Object</font>
getNameFunc仍爲匿名函數,但是return的是this.funAA(),此時,this.funAA變成了在getNameFunc作用域中執行,而不是在window下,驗證了我們之前的猜想:
函數執行環境影響了this作用域
new運算符對this作用域對影響
還是實踐出真理,我們先來寫一段代碼
var a = 2
function test(){
this.a = 1
console.log(window.a)
}
new test()
test()
可以看出輸出結果爲<font color="blue">2,1</font>
new運算符改變了test函數內this的志向,改變的原理是通過在函數內創建一個對象obj,並將test內this作用域指向了obj
類似於
function subNew(){
var obj = {}
var res = test.call(obj,...arguments)
}
subNew() // 作用等於new test()
let/var/const對this作用域的影響
繼續寫代碼通過事實來說明
var a = 1 //函數作用域
let b =1 //塊級作用域
const c = 1 //塊級作用域
function fn(){
this.a = 2
this.b = 2
this.c =2
console.log(this.a,this.b,this.c)
console.log(a,b,c)
//this指向全局作用域 this === window //true
}
fn()
var聲明的變量屬於函數作用域,let/const聲明的變量屬於塊級作用域
可以發現,全局作用域中的a變量被改變,b變量與c變量都沒有被改變,說明在fn()中通過this訪問不到window作用域中的b/c變量
<font color="red">注:這裏說的訪問不到與const定義的變量是常量沒有關係,因爲如果訪問到的話,是會報typeError的</font>
總結
1.this的指向取決於<font color="red">函數執行時</font>所創建運行期上下文(execution context)的內部對象,它會複製父函數的作用域鏈,再在前端插入自己的活動對象,與是否是匿名函數無關
2.在作用域鏈中,var定義的變量屬於函數作用域,可以被子級作用域下的this訪問,而let/const定義的變量數據塊級作用域,不允許在其子級作用域中被訪問
相關知識點
不理解new的實踐可以查看我的這篇文章【Javascript】徹底捋清楚javascript中 new 運算符的實現
對作用域鏈不是很瞭解的同學,可以查看這邊文章【Javascript】深入理解javascript作用域與作用域鏈