理解JavaScript中的this指向

1、常規函數中this

this是使用常規方法調用函數時(call)傳遞的第一個參數,它能夠在函數調用時修改,在函數沒有調用的時候,this的值是沒法肯定的。javascript

1. 純粹的函數調用

常見寫法(簡寫):java

function test(name) {
    console.log(name)
    console.log(this)
}
test('Jerry')  //調用函數
複製代碼

完整寫法:函數

function test(name) {
    console.log(name)
    console.log(this)
}
test.call(undefined, 'Tom')
複製代碼

若是你傳的context 是 null 或者 undefined,那麼 window 對象就是默認的 context(嚴格模式下默認 context 是 undefined)ui

2. 對象中函數的調用

默認thisthis

const obj = {
    name: 'Jerry',
    greet: function() {
        console.log(this.name)
    }
}
obj.greet()  //第一種調用方法(語法糖)
obj.greet.call(obj) //第二種調用方法
複製代碼

手動指定thisspa

const obj = {
    name: 'Jerry',
    greet: function() {
        console.log(this.name)
    }
}
obj.greet.call({name: 'Spike'})  // Spike
複製代碼

3. 構造函數中this

構造函數裏的this稍微有點特殊,每一個構造函數在new以後都會返回一個對象,這個對象就是this,也就是context上下文。code

function Test() {
    this.name = 'Tom'
}
let p = new Test()
console.log(typeof p)  // object
console.log(p.name)    // Tom
複製代碼

new關鍵字會建立一個空的對象,將this指向這個空對象,這樣的話函數內部的this就會被這個空的對象替代。對象

當this碰到return時繼承

function fn() {  
    this.user = 'Jerry';  
    return {};   // undefined
    return function(){};  // undefined
    return 1;  // Jerry
    return undefined;  // Jerry
}
var a = new fn;  
console.log(a.user); 
複製代碼

若是返回值是一個對象,那麼this指向的就是那個返回的對象,若是返回值不是一個對象那麼this仍是指向函數的實例。ip

function fn() {  
    this.user = 'Jerry';  
    return null;
}
var a = new fn;  
console.log(a);  // fn {user: "Jerry"}
複製代碼

雖然null也是對象,可是在這裏this仍是指向那個函數的實例,由於null比較特殊。

4. window.setTimeout()和window.setInterval()中函數的調用

window.setTimeout()和window.setInterval()的函數中的this有些特殊,裏面的this默認是window對象。

2、箭頭函數中的this

MDN官方文檔:箭頭函數不會建立本身的this,它只會從本身的做用域鏈的上一層繼承this。

1. 箭頭函數的特性一:繼承上層this

不使用箭頭函數

const obj = {
	a: function() { console.log(this) }    
}
obj.a()  // {a: ƒ} obj對象
複製代碼

使用箭頭函數

const obj = {
    a: () => {
        console.log(this)
    }
}
obj.a()  // window
複製代碼

2. 箭頭函數的特性二:不能用call方法修改裏面的this

例子

const obj = {
    a: () => {
        console.log(this)
    }
}
obj.a.call('123')  // window
複製代碼

結合window.setTimeout()

const obj = {
    a: function() {
        console.log(this)
        window.setTimeout(() => { 
            console.log(this) 
        }, 1000)
    }
}
obj.a.call(obj)  //第一個this是obj對象,第二個this仍是obj對象
複製代碼

3、多層對象嵌套裏函數的this

例子1

const obj = {
    a: function() { console.log(this) },
    b: {
    	c: function() {console.log(this)}
	}
}
obj.a()  // obj對象, 至關於obj.a.call(obj)
obj.b.c() // obj.b對象, 至關於obj.b.c.call(obj.b)
複製代碼

例子2

const obj = {
    a: function() { console.log(this) },
    b: {
    	c: () => {console.log(this)}
	}
}
obj.a()   // obj對象
obj.b.c()  // window!!
複製代碼

window對象就是它的上一層this,此例中的多層嵌套只是對象嵌套,這時候沒有做用域鏈的嵌套,實際上對箭頭函數來講,仍是隻有本身一級的做用域,和上一層的window做用域

例子3

function fn0() {
    return {
        fn1: function () {
             var obj = {
                a: function() { console.log(this) },
                b: {
        	        c: () => console.log(this)
    	        }
    	    }
    	    return obj;
        }
    }
}

fn0().fn1().b.c() // 獲得{fn1: f} fn1對象
複製代碼

在ES5中,只有全局做用域和函數做用域,並無塊級做用域,因此這裏箭頭函數仍然綁定外層this值,而非根做用域

相關文章
相關標籤/搜索