《javascript高級程序設計》中有說到:javascript
this對象是在運行時基於函數的執行環境綁定的:在全局函數中,this等於window ,而當函數被做爲某個對象調用時,this等於那個對象。不過,
匿名函數具備全局性,所以this對象同常指向window
前端
不過,在全局函數中,this等於window
,匿名函數具備全局性,所以this對象一般指向window
,針對於匿名函數this具備全局性的觀點還是有爭議的,可參考 www.zhihu.com/question/21…java
關於閉包常常會看到這麼一道題:git
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
console.log(object.getNameFunc()());//result:The Window
複製代碼
在這裏,
getNameFunc
return了1個匿名函數,可能你會認爲這就是輸出值爲
The Window
的緣由
可是,咱們再來嘗試寫1個匿名函數github
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())
複製代碼
能夠發現,一樣是匿名函數,卻輸出了
The Window, My Object
在做用域鏈中,執行函數時會建立一個稱爲「運行期上下文(execution context)」的內部對象,運行期上下文定義了函數執行時的環境。閉包
由於函數在全局做用域中被
object.getNameFunc()
獨立調用,funAA的做用域鏈被初始化爲undefined即window的[[Scope]]所包含的對象,致使輸出結果爲window.name函數
對做用域鏈不是很瞭解的同窗,能夠查看這邊文章【Javascript】深刻理解javascript做用域與做用域鏈測試
實踐是檢驗真理的惟一標準,讓咱們用代碼測試一下ui
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())
複製代碼
能夠發現,輸出了
My Object, My Object
getNameFunc仍爲匿名函數,可是return的是this.funAA(),此時,this.funAA變成了由object調用,驗證了咱們以前的猜測:
函數執行環境影響了this做用域,對這個demo的代碼不太理解的同窗,能夠看一下另外一個比較簡單的案例this
this.x = 9;
var module = {
x: 81,
getX: function() { console.log(this.x) }
};
module.getX(); // 81
var retrieveX = module.getX;
function A(){
this.x = 22;
retrieveX() //22
}
A()
複製代碼
仍是實踐出真理,咱們先來寫一段代碼
var a = 2
function test(){
this.a = 1
console.log(window.a)
}
new test()
test()
複製代碼
能夠看出輸出結果爲
2,1
new運算符改變了test函數內this的做用域,改變的原理是經過在函數內建立一個對象obj,並經過
test.call(obj)
,執行
obj.test()
,call函數原理:
Function.prototype.call1 = function(obj,...args){
obj.fn = this
obj.fn(...args)
delete obj.fn
}
複製代碼
這樣test函數被對象obj調用,test複製的是obj的做用域鏈,而不是window
function subNew(){
var obj = {}
var res = test.call(obj,...arguments)
}
subNew() // 做用等於new test()
複製代碼
繼續寫代碼經過事實來講明
var a = 1 // 全局做用域
let b = 1 // 塊級做用域
const c = 1 // 塊級做用域
function foo(){
var d = 1 // 函數做用域
this.a = 2
this.b = 2
this.c = 2
this.d = 2
console.log(a,b,c,d) // 2,1,1,1
}
foo()
複製代碼
a爲全局做用域中的變量,能夠被this對象訪問,b/c/d則不行
能夠發現,全局做用域中的a變量被改變,b變量與c變量都沒有被改變,說明在fn()中經過this訪問不到window做用域中的b/c變量
注:這裏說的訪問不到與const定義的變量是常量沒有關係,由於若是訪問到的話,是會報typeError的
var num = 1
const object = {
num:2,
foo: function(){
return ()=>{
console.log(this.num)
}
}
}
object.foo() // 2
複製代碼
箭頭函數 this 指向 所處環境的上下文的 this 值,與是否獨立調用或做爲屬性被調用,沒有關係。 箭頭函數沒有arguments
/prototype
,不能做爲構造函數,不能使用new
函數執行時
所建立運行期上下文(execution context)
的內部對象,它與當前運行函數的[[scope]]所包含的對象組成了1個新的對象,這個對象就是活動對象
,而後此對象會被推入做用域鏈的前端被某一個對象所擁有
,那麼該函數在調用時,內部的this指向該對象。全局做用域window
中被獨立調用
,那麼該函數內部的this,則指向undefined。可是在非嚴格模式中,當this指向undefined時,它會被自動指向全局對象。非嚴格模式
下,函數內的this對象有能力也僅能訪問到全局做用域中定義的變量即window對象, 塊級做用域/函數做用域內的變量都沒法被訪問所處環境的上下文的 this 值
,與是否獨立調用或做爲屬性被調用,沒有關係。不理解new的實踐能夠查看個人這篇文章【Javascript】完全捋清楚javascript中 new 運算符的實現
對做用域鏈不是很瞭解的同窗,能夠查看這邊文章【Javascript】深刻理解javascript做用域與做用域鏈