面試整理 -- this、apply、call、bind

原文鏈接: 掘金-this、apply、call、bind

一、有關this綁定的案例

this永遠指向最後調用它的那個對象

Demo1:

var name = "windowName";
function a(){
	var name = "innerName";

	console.log(this.name); // 在非嚴格模式下(瀏覽器環境下)結果爲windowName,在嚴格模式下(Node環境下)結果爲undefined

	console.log(this); // 在非嚴格模式下(瀏覽器環境下)結果爲window對象,在嚴格模式下(Node環境下)報錯
}
a();
console.log(this.name); // 在非嚴格模式下(瀏覽器環境下)結果爲windowName,在嚴格模式下(Node環境下)結果爲{}

Demo2:

var name = "windowName";
var obj = {
	name: 'innerName',
	fn: function () { 
		console.log(this.name); // 在非嚴格和嚴格模式下結果都是innerName
	}
}

obj.fn(); // 注: 這次調用函數的是obj對象


// 補充一點,假如把obj中的name換成name1:
var obj1 = {
	name: 'innerName',
	fn: function () { 
		console.log(this.name); //結果就是undefined
	}
}

 

 Demo3: 調用時將obj換成window.obj,  由於最後調用的對象依然是obj,所以打印的結果仍然是innerName 

 Demo4:

// 把obj中的name註釋掉

var name = "windowName";
var obj = {
	// name: 'innerName',
	fn: function () { 
		console.log(this.name);  // undefined
	}
}

obj.fn();

fn的最後一個調用對象是obj,而obj中此時並沒有name屬性,也不會向上一個對象中查找,所以輸出結果爲undefined

 Demo5:

var name = "windowName";
var obj = {
	name: null,
	fn: function () { 
		console.log(this.name); // 非嚴格模式下結果爲windowName
	}
}

var f = obj.fn;
f();

本例中最關鍵的一處在於obj.fn的指向給了f,所以此時調用fn函數的對象並不是obj,而是window,所以輸出結果爲windowName

 Demo6:

var name = "windowName";
function fn(){
	var name = "innerName";
	function innerFn(){
		console.log(this.name); // windowName
				
	}
	innerFn();
}
fn();

我們會以爲innerFn在fn裏面調用this會指向fn, 但是最先執行的函數fn它的指向對象是window,所以innerFn中this的指向也是window,所以打印結果爲innerName

 

二、如何修改this指向

  • 使用ES6箭頭函數
  • 在函數內部使用 var that = this;
  • 使用apply、call、bind
  • new實例化一個對象

思考下面的代碼: 

var name = "windowName";
var obj = {
	name: "innerName",
	func1: function(){
		console.log(this.name);
	},
	func2: function(){
		setTimeout(function(){
			this.func1();				
		},100)
	}
}

obj.func2();

答案是:     

解釋:  雖然func2的調用對象是obj沒錯,但是func2中的setTimeout函數的調用對象其實是window對象,this指向的也就是window對象。 window對象中並沒有func1函數,所以就報錯了。。

2.1 箭頭函數改造

箭頭函數謹記: 箭頭函數的this始終指向函數定義時的this,而非函數執行時。箭頭函數中沒有this綁定,必須通過查找作用域鏈來決定其值。如果箭頭函數被非箭頭函數包含,this綁定的時最近一層非箭頭函數的this,否則this爲undefined

改造後的代碼:

var name = "windowName";
var obj = {
	name: "innerName",
	func1: function(){
		console.log(this.name);
	},
	func2: function(){
		setTimeout( ()=> {
			this.fun1(); // innerName
        },100)
    }
}

obj.func2();

2.2 使用var that = this;保存this指向

var name = "windowName";
var obj = {
	name: "innerName",
	func1: function(){
		console.log(this.name);
	},
	func2: function(){
        var that = this;
		setTimeout(function(){
			that.fun1(); // innerName
        },100)
    }
}

obj.func2();

func2中this的指向時調用func2方法的obj, 在調用setTimeout函數之前,我們先將this賦值給that,那麼that就指向了obj,在setTimeout函數中that也是指向obj。

2.3 使用apply、call、bind修改this指向

2.3.1 使用apply 原先setTimeout函數中的this是指向window,我們需要將其指向obj,在其函數後面使用.apply(obj)即可改變this指向

2.3.2 call 和 bind 用法與上面相同。

面試考點1: apply和call有什麼區別

答: apply和call的區別僅在與傳遞參數的不同,除綁定對象外,apply傳遞的是一個數組,而call傳遞的是參數列表。

例:

var name = "windowName";
var obj = {
	name: 'innerName',
	fn: function(a,b){
		console.log(this.name);
		console.log(a+b);
	}
}
var a = obj.fn;

a.apply(obj,[1,2]) // apply寫法
 
a.call(obj,1,2) // call寫法

面試考點2: apply,call和bind有什麼區別?

調用bind時,會創建一個新的函數,必須要我們手動執行

三、函數的調用方式

  • 作爲一個函數調用
  • 函數作爲方法調用
  • 使用構造函數調用函數
  • 作爲函數方法調用函數

new 的過程:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章