【JavaScript】this指向機制

this指向問題

this機制:this綁定只取決於函數調用的方式,大的來說有三種:

  1. 函數調用:window/undefined
  2. 方法調用:調用對象
  3. 構造函數:返回的實例對象

此外,注意兩點:

  1. 利用call、apply、bind可以改變this指向
  2. 箭頭函數的this繼承外層函數

1. this機制

  • 全局作用域中,window
  • 函數調用(普通調用、IIFE),window
  • 方法調用,綁定到調用對象
  • 隱式丟失(被傳遞給變量或者參數)
var a = 0;
function foo(){
	console.log(this.a);
};
var obj = {
	a: 1,
	foo: foo
};
obj.foo(); // 1
var bar = obj.foo; // 隱式丟失
bar(); // 0
(obj.foo)(); // 1
(obj.foo = obj.foo)(); // 0
  • 顯式綁定 : bind、apply、call (作業幫面試)
  • 硬綁定:綁定後無法修改this
var a = 0;
var obj = {a: 1};
function foo(){
	console.log(this.a);
};
function bar(){
	foo.call(obj);
};
bar(); // 1
var baz = foo.bind(obj);
baz(); // 1
  • 數組內置函數顯示綁定:map forEach filter some every
  • new綁定:構造函數
    • 構造函數一般不使用return語句,通常初始化新對象,當構造函數的函數體執行完畢時,會顯示返回。this指向新返回的實例對象
    • 構造函數使用了return語句,但沒指定返回值,或者返回一個原始值,那麼這時將忽略返回值。返回構造出來的實例對象。
    • 構造函數顯示地使用return語句返回一個對象,this指向這個對象
// 1
function Car(){
	this.counts = 1200;
}
var c = new Car(); // {counts: 1200}

// 2
function Car(){
	this.counts = 1200;
	return;
}
var c = new Car(); // {counts: 1200}

// 3
function Car(){
	this.counts = 1200;
	return {noCounts: 0};
}
var c = new Car(); // {noCounts: 0}
  • 嚴格模式下,獨立調用的函數的this指向undefined
  • 非嚴格模式下,call、apply中的null、undefined會被轉化成window
function Foo(v){
	this.a = v;
};
var obj = {};
var bar = Foo.bind(obj);
bar(0);
console.log(obj.a); // 0
var baz = new bar(1);
console.log(obj.a); // 0
console.log(baz.a); // 1

2. this指向優先級

優先級:new > call/apply/bind > 方法調用 > 函數調用

// 1.
var a = 0;
function foo(){
	function test(){
		console.log(this.a);
	};
	return test;
};
var obj = {
	a: 1,
	foo: foo
}
obj.foo()(); // 0

// 2.
var a = 0;
function foo(){
	var that = this;
	function test(){
		console.log(that.a);
	};
	return test;
};
var obj = {
	a: 1,
	foo: foo
}
obj.foo()(); // 1

3. 箭頭函數

  • 箭頭函數:改變this機制,不再只是根據函數調用方式決定;箭頭函數會繼承外層this指向 —> 這直接解決了var that = this;的寫法
  • call/apply/bind 無法改變箭頭函數的this指向
var a = 0;
function foo(){
	var test = () => this.a;
	return test;
};
var obj1 = {
	a: 1,
	foo: foo
};
var obj2 = {
	a: 2,
	foo: foo
};
obj1.foo().call(obj2); // 1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章