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
回過頭來,文章開頭的“開胃菜”,是不是有答案了!