前言
JavaScript中this變量是一個令人難以摸清的關(guān)鍵字抹估,當初學習javascript的時候被這個this指向問題折騰的我是慘不忍睹琅轧,漏洞百出衷戈。一度想在后面的代碼過程中放棄對this的使用,但是this在javascript當中用處太廣泛了酱讶。
充分了解this的相關(guān)知識有助于我們在編寫面向?qū)ο蟮腏avaScript程序時能夠游刃有余围苫,沒辦法只能硬著頭皮上呀裤园。被虐多次再結(jié)合自己查閱相關(guān)文檔資料,總算有一點小小心得剂府。特分享出來拧揽,供大家參考!
this簡述
關(guān)于this的清this所引用的對象到底是哪一個腺占,也許很多資料上都有自己的解釋淤袜。例如我鐘愛的《高三》對this也是簡單幾頁翻過。最后翻閱到MDN上面的wen技術(shù)文檔湾笛,上面解釋深得我意饮怯。
在絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了this的值嚎研。this不能在執(zhí)行期間被賦值,在每次函數(shù)被調(diào)用時this的值也可能會不同库倘。
--MDN社區(qū)web技術(shù)文檔
由此可以推出this的在不同的情況下临扮,this的指向各不相同。簡單來說就分為5種情況
1教翩、全局環(huán)境
var a = "先制定一個小目標杆勇,下一頓飯加一個雞腿";
console.log(this); // 這里this就指向 window
console.log(this.a); //控制臺輸出 "先制定一個小目標,下一頓飯加一個雞腿"
這一種情況相信大家都非常好理解饱亿,在全局環(huán)境當中this默認是指向window
2蚜退、函數(shù)中調(diào)用
function foo1() {
function bar() {
console.log(this);
}
bar();
}
foo1(); // 輸出window
當foo1()執(zhí)行的時候 ,間接相當于window.foo1()執(zhí)行函數(shù)中的this是指向window彪笼,因此控制臺相應(yīng)輸出window結(jié)果钻注。(foo1() 間接也等于 window.foo1(),這樣就是相當于window在調(diào)用這個函數(shù),因此this也是指向于window配猫。)
3幅恋、對象中調(diào)用
var x = "今天交房租";
var obj = {
foo:function() {
console.log(this.x);
},
x:"房租減免";
};
obj.foo(); //控制臺輸出 "房租減免"
這是當對象obj調(diào)用foo()函數(shù)泵肄,this指向了這個調(diào)用對象捆交,即this就等于obj淑翼,控制臺式輸出就變成了obj.最后控制臺便輸出 "房租減免",唉F纷贰玄括!這要是從房東嘴巴里面輸出該多好!肉瓦!
4惠豺、構(gòu)造函數(shù)中
var name = "hahaha";
function Obj() {
this.name = "CheDabang";
}
var person = new Obj();
console.log(person.name); //輸出 CheDabang
這里通過new運算符創(chuàng)建一個 Obj的對象實例。
變成person{this.name}
风宁,因此這里this的指向也隨著指向這個新實例對象洁墙。因此控制臺輸出 CheDabang
5、apply戒财、call中調(diào)用
當一個函數(shù)的函數(shù)體中使用了this關(guān)鍵字時热监,通過所有函數(shù)都從Function對象的原型中繼承的call()方法和apply()方法調(diào)用的時候,它的值可以綁定到一個指定的對象上饮寞。
function add(c, d){
return this.a + this.b + c + d;
}
var o = {a:1, b:3};
console.log(add.call(o, 5, 7)); //1 + 3 + 5 + 7 = 16
console.log(add.apply(o, [10, 20])); // 1 + 3 + 10 + 20 = 34
小練習
以上就是我們常常出現(xiàn)的5種情況孝扛,看到這么多情況的介紹。諸位看官幽崩,也暈了吧苦始。不要著急,讓我們再來幾個小練習感受一下這位this大爺的指向慌申。
題目①
Code
var a = 10;
function test(){
a = 5;
console.log(a);
console.log(this.a);
var a ;
console.log(this.a);
console.log(a);
}
test();
new test();
當調(diào)用test()的時候,控制臺分別輸出 5柒爵、10役电、10、5
當調(diào)用 new test()的時候棉胀,控制臺分別輸出 5法瑟、undefined、undefined唁奢、5
解析
當var a = 10
==> var window.a = 10
;
當test()調(diào)用的時候霎挟,間接也相當于window.test()調(diào)用。因此當這個函數(shù)執(zhí)行的時候驮瞧,這里面的this指向的是window對象氓扛,因此this.a 指向的是window = 10;
當new test() 實例化,因此this指向的是這個實例的對象采郎,因此這個新對象的a千所,并沒有直接定義過。所以控制臺輸出undefined
題目②
Code
var Funllname = "john Doe";
var obj = {
Funllname:"Colin Thrig",
prop:{
getFullname:function(){
return this.Funllname;
}
},
};
console.log(obj.prop.getFullname());
var test = obj.prop.getFullname;
console.log(test());
控制臺輸出
undefined
john Doe
解析
控制臺結(jié)果1:當obj.prop.getFullname()
在調(diào)用的時候蒜埋,相當于執(zhí)行了其中的函數(shù)淫痰。而由于調(diào)用這個函數(shù)的是obj.prop調(diào)用的,因此this就直接指向obj.prop整份,但是obj.prop這個對象當中并沒有定義Fullname,因此輸出undefined
待错。
控制臺結(jié)果2:當var test = obj.prop.getFullname;
這個時候就間接相當于==>var test = function(){return this.Funllname;}
因此當test()調(diào)用的時候,就相當于 ==> window.test();,因此其中的this便指向了window對象烈评,所以便輸出了 john Doe
題目③
Code
var sex = "male";
var saySex = {
sex:"female",
saySex:function(){
function getSex(){
console.log("this.sex="+this.sex);
}
getSex();
}
}
saySex.saySex();
控制臺輸出
this.sex = male
解析
控制臺結(jié)果:當saySex.saySex()
調(diào)用的時候火俄,只是相當saySex的函數(shù)被調(diào)用。之后在函數(shù)中讲冠,函數(shù)getSex()被調(diào)用瓜客,此時this便指向getSex().而函數(shù)getSex()默認情況下是指向window的,因此這里輸出this.sex = male
題目④
Code
var name = "chedabang";
function sayName(){
var a = {
name:"加一個雞腿",
sayName:getName
};
function getName(){
console.log(this.name);
}
getName();
a.sayName();
getName.call(a);
}
sayName();
控制臺輸出
chedabang
加一個雞腿
加一個雞腿
解析
當sayName()運行的時候時候竿开,先是里面的第一個函數(shù)運行谱仪,getName().因此因此其中的this,便默認指向了window否彩,因此this.name ==> chedabang
其次a.sayName()運行疯攒,因為sayName = getName。所以即當于getName再次被調(diào)用列荔,由于存在調(diào)用對象a敬尺。因此此時this又重新指向?qū)ο骯,對象 a 當中存在name屬性肌毅,因此輸出加一個雞腿
筷转。
最后 getName.call(a).運行的時候,將對象a給綁定到上面悬而,因此函數(shù)里面的this就不指向window,而指向的是綁定的對象a锭汛,因此輸出 加一個雞腿
題目⑤
Code
var a = {
name:"張三",
sayName:function(){
console.log("this.name="+this.name);
}
};
var name = "李四";
function sayName1(){
var sss = a.sayName;
sss();
a.sayName();
(a.sayName)();
(b = a.sayName)();
}
sayName1();
控制臺輸出:
this.name=李四
this.name=張三
this.name=張三
this.name=李四
解析
當sayName1()運行的時候笨奠,sayName1函數(shù)內(nèi)部首先是
控制臺結(jié)果1:var sss = a.sayName
==> var sss = function(){console.log("this.name="+=this.name);}
像前面我們總結(jié)的一樣函數(shù)中調(diào)用,因此這里的this指向window對象唤殴,因此輸出this.name=李四
控制臺結(jié)果2:a.sayName();
這里a直接調(diào)用其中的匿名函數(shù)般婆,因此此時this指向a,因此a.name = "張三"朵逝,所有控制臺輸出this.name=張三
控制臺結(jié)果3:這里(a.sayName)();
其實間接相當于 == a.sayName();
這里指的是值立即執(zhí)行蔚袍。不管如何始終是對象a在調(diào)用sayName這個函數(shù)。因此控制臺也就跟著一起輸出this.name=張三
。
控制臺結(jié)果4:和控制臺結(jié)果3一樣啤咽,代表變量b立即執(zhí)行晋辆,而b和控制臺結(jié)果1中sss一樣,也屬于函數(shù)中調(diào)用宇整,因此this這里指向window瓶佳。即控制臺輸出this.name=李四