this
this
的值:當前執行代碼的環境對象,this
的指向不取決於它在什麼位置建立,徹底取決於函數在什麼地方被調用,this
不能在執行期間被賦值,而且在每次函數被調用時this的值也可能會不一樣。javascript
this
的值在全局環境(任何函數調用的外部)中,this
的值都是全局對象(瀏覽器中是window
對象,node中是global
對象)html
在函數內部環境,this
的值取決於函數被調用的方式java
this
指向規則簡單總結一個原理:this 永遠指向最後調用它的那個對象node
直接調用函數的時候this
指向的是全局對象後端
var name = 'Window.name'
function foo() {
console.log('this',this.name)
}
foo() // Window.name
複製代碼
注意:若是使用的是嚴格模式的話,全局對象是undefined
數組
var name = 'Window.name'
function foo() {
'use strict'
console.log('this',this.name)
}
foo() // Uncaught TypeError: Cannot read property 'name' of undefined
複製代碼
當函數做爲對象的屬性被調用的時候就屬於隱式綁定,這個時候,this指向的是這個函數的對象瀏覽器
var obj = {
num:0,
add:function() {
console.log('this',this) // this {num: 0, add: ƒ}
this.num +=1
}
}
obj.add()
console.log('obj',obj) // obj {num: 1, add: ƒ}
複製代碼
在看下面一個栗子:app
var name = 'ahwgs'
var obj = {
name:'aaa',
foo:function() {
console.log('name',this.name)
}
}
var res = obj.foo
res() // ahwgs
複製代碼
申明一個obj
對象,雖然將obj.foo
的引用賦值給res
,但實際上此時是res()
是不帶修飾的函數調用(屬於第一種函數綁定的狀況),因此此時打印的值是ahwgs
函數
下面咱們作一點改動:ui
var name = 'ahwgs'
var obj = {
name:'aaa',
foo:function() {
console.log('name',this.name)
}
}
obj.foo() // name aaa
複製代碼
這就是正常的隱式調用,這時候的this
爲obj
自己
在看一個栗子:
var name = 'ahwgs'
function doFoo(fn) {
console.log('fn',fn)
fn() //f(){console.log('name',this.name)} fn=obj.foo
}
var obj = {
name:'aaa',
foo:function() {
console.log('name',this.name)
}
}
doFoo(obj.foo) // name ahwgs
複製代碼
這時候,obj.foo
做爲參數傳遞給了doFoo
,實際上調用仍是doFoo
,這時候this
指向的是全局對象,因此打印的是ahwgs
最後一個栗子:
var name = 'ahwgs'
function foo() {
var name = 'aaa'
fn()
function fn() {
console.log('name',this.name)
}
}
foo() // ahwgs
複製代碼
借用開頭說的一句話,this指向的是這個函數所屬的對象因此,fn
指向的是全局對象
使用call/apply/bind
方法進行顯式綁定
var name = 'ahwgs'
function foo() {
console.log('this',this)
console.log('name',this.name)
}
var obj = {
name:'obj'
}
foo.apply(obj) // name obj
foo.call(obj)// name obj
foo.bind(obj)()// name obj
複製代碼
這時候的this
指向都被顯式綁定至obj
,此後,不管如何調用函數,總會將obj綁定到foo中的this上。
new
綁定經過new
關鍵字調用的函數,屬於new
綁定模式。這時this
關鍵字指向這個新建立的對象。
function User(name,age) {
this.name = name
this.age = age
this.getInfo = function() {
console.log('info',this.name + '--->'+this.age)
}
}
var user = new User('ahwgs',20)
console.log(user) // User {name: "ahwgs", age: 20, getInfo: ƒ}
console.log(user.getInfo()) // info ahwgs--->20
複製代碼
this
指向箭頭函數的 this 始終指向函數定義時的 this,而非執行時,箭頭函數中沒有 this
綁定,必須經過查找做用域鏈來決定其值,若是箭頭函數被非箭頭函數包含,則 this
綁定的是最近一層非箭頭函數的 this
,不然,this 爲 undefined
。
看一個栗子:
var name = 'ahwgs'
var obj = {
name:'aaa',
foo1:function() {
console.log('this.name',this.name)
},
foo2:function() {
setTimeout(()=>{
this.foo1()
},100)
}
}
obj.foo2() // aaa
複製代碼
因爲定時器中使用的是箭頭函數的形式,上一級沒有使用箭頭函數,因此this
綁定的是最近一層非箭頭函數的this
,在這裏,即obj
const self = this
var name = 'ahwgs'
var obj = {
name:'aaa',
foo1:function() {
console.log('this.name',this.name)
},
foo2:function() {
var self = this
setTimeout(function() {
self.foo1()
})
}
}
obj.foo2() // aaa
複製代碼
定義一個變量,將當前的this
指向改變至self
中,這樣調用foo1
的時候this
指向就是obj
這個對象
apply、call、bind
先看一下這三個函數的使用方法:
apply
function.apply(obj, [param1,params2,...]) // obj:要綁定的this // 第二個參數:類數組或數組,做爲function的參數傳入 // 當即執行 複製代碼
call
function.call(obj, param1, param2, ...) // obj:要綁定的this // 第二個參數:函數運行的參數,用逗號隔開 // 當即執行 複製代碼
bind
function.bind(obj, param1, param2, ...) // obj:要綁定的this // 第二個參數:函數運行的參數,用逗號隔開 // 返回一個函數 複製代碼
下面使用這三種方法修改this
指向
apply
var name = 'ahwgs'
var obj = {
name:'aaa',
foo1:function() {
console.log('this.name',this.name)
},
foo2:function() {
setTimeout(function() {
this.foo1()
}.apply(obj),100)
}
}
obj.foo2() // aaa
複製代碼
call
var name = 'ahwgs'
var obj = {
name:'aaa',
foo1:function() {
console.log('this.name',this.name)
},
foo2:function() {
setTimeout(function() {
this.foo1()
}.call(obj),100)
}
}
obj.foo2() // aaa
複製代碼
bind
var name = 'ahwgs'
var obj = {
name:'aaa',
foo1:function() {
console.log('this.name',this.name)
},
foo2:function() {
setTimeout(function() {
this.foo1()
}.bind(obj)(),100)
}
}
obj.foo2() // aaa
複製代碼
注意:bind
與其餘兩種方法不一樣,由於他返回的是一個函數,因此須要咱們()
去調用它。
null/undefined
做爲bind/call/apply
的參數var name = 'ahwgs'
var obj = {
name:'aaa',
foo1:function() {
console.log('this.name',this.name)
},
foo2:function() {
setTimeout(function() {
this.foo1()
}.call(null),100)
}
}
obj.foo2() //Uncaught TypeError: this.foo1 is not a function
複製代碼
若是使用null/undefined
做爲參數的話,被調用的時候會被忽略,因此調用obj.foo2()
的時候this
指向的是全局對象,而全局對象中卻沒有foo2
這個函數,因此報錯。
new
實例化新對象可看上述new
綁定實例
this
指的是容許的上下文環境,與後端語言不一樣this
不是一成一變的,會隨着環境而變化this
也不同this
的指向