this 是 js 中的關鍵字,看起來很混亂,但其實很好理解,用網上通用的一句話來講就是: this 的指向在函數定義時肯定不了,只有函數指向的時候才能肯定 this 到底指向誰,也便是說this的卒中指向的是那個調用他的對象javascript
總結起來就六個字 誰調用,指向誰
java
例子1數組
function foo() {
var name = "我愛js";
console.log("this", this); // this window
console.log("name", this.name)// this undefined
}
foo()
複製代碼
爲何這裏的 this 是window對象,由於咱們是在全局做用域中調用的,其實是省略了 window. 看以下代碼的調用方式,跟上一個徹底相同bash
例子2app
function foo() {
var name = "我愛js";
console.log("this", this); // this window
console.log("name", this.name)// this undefined
}
window.foo()
複製代碼
效果跟上面是徹底相同的函數
例子3ui
var foo = {
name: "JavaScript",
child: function () {
console.log("this", this) // this {name: "JavaScript", child: ƒ}
console.log("name", this.name) //name JavaScript
}
}
foo.child()
複製代碼
在這裏調用者是 foo, 因此this指向的是 foo 然而事實是這樣嗎,再看看上面的例子this
例子4spa
var foo = {
name: "JavaScript",
child: function () {
console.log("this", this) // this {name: "JavaScript", child: ƒ}
console.log("name", this.name) //name JavaScript
}
}
window.foo.child()
複製代碼
這裏最終調用者是window,可是this並無指向window,這是怎麼回事?難道是六字真言有問題?要弄懂這個問題,咱們須要再看幾個例子prototype
例子5
var foo = {
a: 1,
b: {
a: 2,
fn: function() {
console.log(this.a) // 2
}
}
}
foo.b.fn()
複製代碼
並且這個例子中的this也一樣沒指向foo, 看到這裏,可能會有疑惑,會推翻六字箴言,可是,若是再補充幾句話,就會消除歧義
非嚴格模式下,若是一個函數中有this,而且這個this沒有被上一級調用,那麼這個this的指向就是window,具體參考例子1,例子2
若是一個函數中有this,這個函數被上一級對象調用,那麼this就指向上一級對象,具體參考例子3
若是一個函數有this,假如調用這個函數的有多級對象,那麼this指向的是調用它的上一級對象,具體參考例子5
咱們再來驗證一下狀況3 例子 6
var foo = {
a: 1,
b: {
//a: 2,
fn: function() {
console.log(this.a) // undefined
}
}
}
foo.b.fn()
複製代碼
此時,咱們看到,輸入的值是undefined,也就是說,這個時候this指向的是b的做用域,而b中沒有定義a,因此輸出的是undefined 然而一切並非依靠想象,總有狀況例外,咱們看下一個例子
例子7
var foo = {
a: 1,
b: {
a: 2,
fn: function() {
console.log(this) // window
console.log(this.a) // undefined
}
}
}
var tm = foo.b.fn
tm()
複製代碼
從這個例子中咱們看到,this指向的是window,這是怎麼回事?其實很好理解,還記得六字箴言嗎?誰調用,指向誰
,這一句var tm = foo.b.fn
只是進行了賦值,把 fn
賦值給了全局變量 tm
,然而最終的調用時機是在 window做用域調用的函數 tm()
, 因此 this的指向是window對象。至此, this 的指向已經完畢
就六個字 誰調用,指向誰
,另加幾個條件
非嚴格模式下,若是一個函數中有this,而且這個this沒有被上一級調用,那麼這個this的指向就是window
若是一個函數中有this,這個函數被上一級對象調用,那麼this就指向上一級對象
若是一個函數有this,假如調用這個函數的有多級對象,那麼this指向的是調用它的上一級對象
一般狀況下,咱們想使用其它環境變相下的狀態,這就須要藉助this來實現,經常使用改變this指向的有如下幾種方式能夠實現
先看這個例子 例子8
function Foo () {
this.name = 'Justin'
}
var f = new Foo()
console.log(f.name) // Justin
複製代碼
在使用 new 關鍵字調用構造函數時,會依次執行
prototype
賦值給這個新對象的 __proto__
假如函數中有 return, 來看看this的指向? 看下面這個例子 例子9
function Foo () {
this.name = 'Justin'
return {}
}
var f = new Foo()
console.log(f.name) // undefined
複製代碼
在這裏, 輸出的是undefined,也就是說,this根本沒有指向 f, 那麼this到底指向哪裏了呢 其實,若是一個返回值是對象,那麼this指向的就是返回的對象, 若是反回的不是對象,那麼指向的仍是指向函數的實例, null除外
例子10 利用下面幾個例子驗證
function Foo () {
this.name = 'Justin'
return function(){}
}
var f = new Foo()
console.log(f.name) // undefined
複製代碼
例子11
function Foo () {
this.name = 'Justin'
return 1
}
var f = new Foo()
console.log(f.name) // Justin
複製代碼
例子12
function Foo () {
this.name = 'Justin'
return undefined
}
var f = new Foo()
console.log(f.name) // Justin
複製代碼
例子13
function Foo () {
this.name = 'Justin'
return null
}
var f = new Foo()
console.log(f.name) // Justin
複製代碼
以上跟第三點總結相符合,至此,構造函數改變this指向解析完畢
例子13
var w = "流星火雨"
var obj = {
name: "黃忠",
w: this.w,
state: function(name, ow){
console.log(`${this.name} 的 w 技能是 ${this.w}`)
}
}
var skills = {
name: '馬岱',
w: "紫電箭雨"
}
obj.state() // 忠 的 w 技能是 undefined
obj.state.call(skills) //馬岱 的 w 技能是 紫電箭雨
obj.state.apply(skills) //馬岱 的 w 技能是 紫電箭雨
obj.state.bind(skills) //馬岱 的 w 技能是 紫電箭雨
複製代碼
從上面看出來, call, apply, bind把this的指向改變爲call, apply, bind所傳入的第一個參數, 除此以外,他們是沒有什麼區別的
先看一個例子
var w = "流星火雨"
var obj = {
name: "黃忠",
w: this.w,
state: function(HeroType, HP){
console.log(`${this.name} 的 w 技能是 ${this.w}, 他是一個 ${HeroType}, 他的血量是${HP}`)
}
}
var skills = {
name: '馬岱',
w: "紫電箭雨"
}
obj.state() // 忠 的 w 技能是 undefined
obj.state.call(skills, "法師", 100) //馬岱 的 w 技能是 紫電箭雨
obj.state.apply(skills, ["法師", 100]) //馬岱 的 w 技能是 紫電箭雨
obj.state.bind(skills, "法師", 100)() //馬岱 的 w 技能是 紫電箭雨
複製代碼
不一樣的是, apply第二個參數接受的是一個數組, call 直接按參數排列就能夠了,而 bind 跟call類似,只不事後面多了個 ()
最後,再加一個複雜的案例
function foo() {
let args = Array.prototype.slice.apply(arguments)
console.log("args", args) //[ '國家隊', '黃忠', '典韋', '張瑩瑩', '黃蓋', '許褚' ]
}
foo("國家隊", "黃忠", "典韋", "張瑩瑩", "黃蓋", "許褚")
複製代碼
更多請參考: www.iquanku.com/admin/28.ht…