Js this指向

this,這個!

This is mine.  這個是我的!

This is yours. 這個是你的!

世間萬物,皆有所屬!你的,我的,她的!哪怕失物,無人領取,也會歸於公共名下!

 

今天來聊聊 this,如果要用到JS,this 是避不開的話題,this之於JS ,像自拍之於女人,iPhone之於手機!

來來來,正餐之前,先來一道開胃菜:

function Fx(){
	this.a = 1;
	this.b = 2;
}
Fx.prototype.getInfo = function(){
	console.log(this.a);
}
const fx = new Fx();

const obj = {
	a:3,
	getInfo: fx.getInfo 
}

fx.getInfo();	
obj.getInfo();

注:本文所有測試均在非嚴格模式下執行!

結果:1,3 

爲什麼 obj.getInfo() 的結果是3,而不是1?

 

帶着問題,從兩個方面來了解 this

一、this 只與函數的執行環境有關,而與聲明環境沒有關係。

打個不恰當的比喻,好比你的iPhoneX手機,有 faceId 識別功能,()符號代表使用。

你自己用手機,faceId識別-這個是你的,但把你的手機給老王,faceId就懵了,這個不知道是誰!this亦然,關鍵在誰使用/執行:()    

var name = "未知";

· 構造函數: 

function iPhoneX(){
	this.name = "Marc";
	this.faceId = function(){
		console.log(this.name);
	}		
}
var phone = new iPhoneX();
//自己用
phone.faceId();

//老王用
var wang = phone.faceId;
wang();

  結果:"Marc"、"未知"

 

· 對象 

var ipx = {
	name:"Marc",
	faceId: function(){
		console.log(this.name);
	}	
}
//自己用
ipx.faceId();
//老王用
var odlWang = ipx.faceId;
odlWang();

 結果:"Marc"、"未知"

 

· DOM

<button id="wang" name="wang">iphoneX</button>
var ipx = {
	name:"Marc",
	faceId: function(){
		console.log(this.name);
	}	
}	
ipx.faceId();
document.getElementById("wang").onclick = ipx.faceId;

  結果:"Marc"、"wang"

 

二、在非箭頭函數下, this 指向調用其所在函數的對象,指向遵循就近原則

如果箭頭函數被非箭頭函數包含,則 this 綁定的是最近一層非箭頭函數的 this。

 

先定義一個全局變量,不同應用場景來測試:

var num = 1;

 

1、全局

console.log(this.num);

結果:1,指向Window 對象,等同於:window.num;

 

2、對象

var obj = {
	num:4,
	info:function(){
		console.log(this.num);		
	}
}
obj.info();

結果:1,指向 定義的對象 obj;

當然,取變量:console.log(num);  還是 1

 

3~6 分別是,this的4種綁定規則:默認綁定、隱式綁定、顯示綁定、new 綁定。優先級從低到高!

 

3、默認綁定

普通函數,將全局對象綁定this上

function fn(num){
	console.log(this.num);			
}
fn(2)

結果:1,指向Window 對象;等同於:window.fn();

console.log(num);  結果纔是:2

 

4、隱式綁定

需要特別注意第二種情況!

function f1() { 
    console.log( this.num );
}
var obj1 = { 
    num: 2,
    f1: f1 
};
//第一種情況
obj1.f1();

//第二種情況
var demo1 = obj1.f1;
demo1();

結果:2,1

 

5、顯示綁定 call、apply

this就指向第一個參數,如果是null,則指向window 

Array.prototype.pow = function(arr){
	console.log(this);			
	for (var i = 0; i < this.length; i++) {				
		arr.push(Math.pow(this[i],2));
	}
	return  arr;
}
Array.prototype.pow.call([1,3,5],[]);

結果:[1,3,5]  

 

6、new 綁定

構造函數,this會指向對象實例

function Fx(){
	this.num = 3;
	_this = this;			
}		
var fx = new Fx();
console.log(fx.num);
console.log(fx === _this);

結果:3、true ,指向 實例 fx;

 

7、多層調用鏈

function f2() { 
    console.log( this.num );
}
var obj2a = { 
    num: 2,
    f2: f2 
};
var obj2b = { 
    num: 3,
    obj2a: obj2a
};
//第一種情況
obj2b.obj2a.f2(); 

//第二種情況
var demo2 = obj2b.obj2a.f2;
demo2();

結果:2,1

 

8、構造函數內 return

構造函數,如果返回值是一個對象(null 除外),this指向返回的對象,否則還是指向構造函數的實例!

· 返回函數、數組、對象

function F1()  
{  
    this.num = 2;  
    return {};  // return function(){};  ||  return [];  
}
var f1 = new F1;  
console.log(f1.num); 

結果:undefined

· 返回 undefined、字符串、數字、null、布爾值

function F2()  
{  
    this.num = 2;  
    return 1;  //return undefined; ||return null; || return "123"; ||return true/false;  
}
var f2 = new F2;  
console.log(f2.num);

結果:2

 

9、定時器

.定時器(匿名函數)內沒有默認的宿主對象,所以this指向window

var timer1 = setInterval(function(){
	console.log(this===window);
},300);
//clearInterval(timer1);

var timer2 = setTimeout(function(){
	console.log(this===window);
},300);
//clearTimeout(timer2);

結果:true,true

 

10、DOM  

this 指向觸發事件的 DOM 元素本身

<ul class="list">
	<li>list1</li>
	<li>list2</li>
	<li>list3</li>
	<li>list4</li>
</ul>
var elems = document.getElementsByClassName("list")[0].getElementsByTagName("li");
for (var i = 0; i < elems.length; i++) {
	elems[i].index = i;
	elems[i].onclick = function(){
		console.log(this);
	}
}	

 

11、箭頭函數

如果箭頭函數被非箭頭函數包含,則 this 綁定的是最近一層非箭頭函數的 this

var obj = {
	num:5,			
	info:()=>console.log(this.num),
	person:{
		name:"Marc",
		age:18,
		num:6,
		card:()=>console.log(this.num)			
	},
	car:function(){
		return ()=> console.log(this.num);
	}

}
obj.info();
obj.person.card();
obj.car()();

結果:1,1,5

如果這樣呢:

var card =  obj.person.card;    card();
var car1 = obj.car;             car1()();
var car2 = obj.car();           car2();

結果:1,1,5

 

回過頭來,文章開頭的“開胃菜”,是不是有答案了!

 

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