前言
對于一個前端初學者來說,this的指向是一個必須要掌握的知識點,尤其是es6之後的this指向更加變得飄忽不定,我們今天就來了解一下各種情況下this的指向。
什麼是this
首先,this不是一個函數也不是某個對象,它具體指向什麼東西取決于我們在哪裡去調用這個this,隻有函數調用的時候才會發生this的綁定
1.全局作用域
console.log(this === window) //true
當我們在全局作用域中調用的時候,this指向的是window對象,相當于window調用的這個tihs
2.純函數調用
function fun(){
console.log(this)//this指向window
}
fun()
複制
為什麼在函數體内this也是指向的window,我們可以看到是在全局調用的fun函數,當我們調用的時候會進行預設綁定,也就是綁定到window上。
3.作為對象方法和對象的屬性值
var Person = {
name:'張三',
that:this,
age:function(){
console.log(this)//Person對象
console.log(this.name)//李四
}
}
console.log(Person.that) //window 類似純函數調用
Person.age() //調用對象的age方法
複制
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAjM2EzLcd3LcJzLcJzdllmVldWYtl2Pn5GcugHb1QGayYnNhRzLcVDO0YTNyczLcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.png)
當我們把this作為對象的某個方法去調用的時候,this指向的是這個對象,相當于這個對象調用這個方法
var Person = {
obj:{
name:'李四',
sex:function(){
console.log(this)//obj對象
}
}
}
Person.obj.sex()//調用penson對象中的obj對象的sex方法
複制
嵌套對象的時候this的指向同樣是誰調用指向誰,這時候是obj對象調用的
4.構造函數中的this
function fun(name,age){
this.name = name;
this.age = age;
}
var obj = new fun('李四',20)
console.log(obj)//控制台列印如下
複制
這時候的this指向的是構造函數所建立出來的obj對象
5.class類中的this
class Person {
constructor(name){
this.name = name
this.say = function () {
console.log('my name is '+ this.name)
}
}
sleep = function(){
console.log(this)
}
}
var objA = new Person('李四')
objA.say()//調用objA對象的say方法 控制台列印 ‘my name is 李四’
objA.sleep()//調用objA對象的sleep方法 列印 objA對象
複制
在class中的this都是指向這個構造函數生成的對象
6.es6中的箭頭函數this指向
var obj = {
name:'張三',
say:()=>{
console.log(this)
}
}
obj.say()//控制台列印window
複制
箭頭函數沒有自己的this 會預設繼承父級執行上下文的this,這裡的上下文this就是window
注:當函數執行時,會建立一個稱為執行上下文的内部對象(可了解為作用域)。一個執行上下文定義了一個函數執行時的環境。對象是沒有執行上下文的。
--
var obj = {
name:'李四',
person:function() {
return {
name:'張三',
say:()=>{
console.log(this)
}
}
}
};
obj.person().say()//調用say方法這裡的this指向的是obj對象,箭頭函數沒有this會向上查找。普通函數建立時會綁定this,如果person函數也是箭頭函數的話this指向window
複制
更改this指向(面試經常問到)
var Person = {
name:'張三',
say:function(age){
console.log(`my name is ${this.name},i am ${age} years old`)//es6文法模闆字元串
}
}
var obj = {
name:'李四'
}
複制
直接調用
Person.say()
bind()
Person.say.bind(obj,'20','第二個參數',...)()//bind傳回的是一個重新綁定this的函數需要調用
Person.say.bind(obj)('20','第二個參數',...)//兩種傳參方式,參數依次加在後面
複制
call
Person.say.call(obj,'20','第二個參數',...)//call傳回的是重新綁定this并且立即調用之後的結果,參數依次加在後面
複制
apply
Person.say.apply(obj,['20','第二個參數'])//傳回的同樣是綁定了this并且立即調用之後的結果,參數是數組格式
複制
總結:
bind 跟 call和apply相比 差別顯而易見,傳回的結果不同 需要自己去調用,那麼call跟apply有什麼差別呢?其實除了傳參方式不同并沒有很大的差別,有傳聞apply對記憶體的消耗更小一點,因為基本資料類型和引用資料類型在記憶體中存放的方式不同,具體是不是還需要去驗證一番。
本文為作者原創,手碼不易,允許轉載,轉載後請以連結形式說明文章出處。