一债热、this在函數(shù)調(diào)用時
const fun1 = function () {
? ? ? ? console.log(this);
? ? ? ? const fun2 = function () {
? ? ? ? ? ? console.log(this);
? ? ? ? };
? ? ? ? fun2(); //輸出 Window
? ? };
? ? fun1();? //輸出 Window
然而嚴(yán)格模式下,結(jié)果并不相同挑围;
```'use strict'
? ? const fun1 = function () {
? ? ? ? console.log(this);
? ? ? ? const fun2 = function () {
? ? ? ? ? ? console.log(this);
? ? ? ? };
? ? ? ? fun2(); //輸出 undefined
? ? };
? ? fun1();? //輸出 undefined
?fun1這個函數(shù)是全局的倔喂,默認(rèn)掛載在window對象下铝条,this指向它的調(diào)用者即window,所以輸出window對象席噩,但是在嚴(yán)格模式下班缰,this不允許指向全局變量window,所以輸出為undefined悼枢。
fun2在函數(shù)直接調(diào)用時默認(rèn)指向了全局window鲁捏,實(shí)際上js設(shè)計上的缺陷。正確的方式應(yīng)該是內(nèi)部函數(shù)的this 應(yīng)該綁定到其外層函數(shù)對應(yīng)的對象上萧芙,使用變量替代的方式規(guī)避該問題。
?二假丧、this作為對象方法
const user = {
? ? ? ? userName: '張三',
? ? ? ? age: 18,
? ? ? ? selfIntroduction: function () {
? ? ? ? ? ? const str = 'str 我的名字是:' + this.userName + ",年齡是:" + this.age;
? ? ? ? ? ? console.log(str);//str 我的名字是: 張三,年齡是:18
? ? ? ? ? ? const loop = function () {
? ? ? ? ? ? ? ? console.log('loop 我的名字是:' + this.userName + ",年齡是:" + this.age);
? ? ? ? ? ? };
? ? ? ? ? loop();? ? //loop 我的名字是:undefined,年齡是:undefined
? ? ? ? }
? ? };
user.selfIntroduction();? ?
selfIntroduction()方法的調(diào)用者是user双揪,所以在該方法內(nèi)部this指向了他的父對象user,而loop方法輸里面指向的window包帚,所以才會輸出undefined渔期;所以我嘗試修改下,將方法內(nèi)的this緩存下來渴邦,將loop方法的this指向修改
const user = {
? ? ? ? userName: '張三',
? ? ? ? age: 18,
? ? ? ? selfIntroduction: function () {
? ? ? ? ? ? const str = 'str 我的名字是:' + this.userName + ",年齡是:" + this.age;
? ? ? ? ? ? console.log(str); //str 我的名字是: 張三,年齡是:18
? ? ? ? ? ? const that=this;
? ? ? ? ? ? const loop = function () {
? ? ? ? ? ? ? ? console.log('loop 我的名字是:' + that.userName + ",年齡是:" + that.age);
? ? ? ? ? ? };
? ? ? ? ? ? loop();? ? //loop 我的名字是: 張三,年齡是:18
? ? ? ? }
? ? };
user.selfIntroduction();?
小結(jié):將selfIntroduction()賦值給了全局變量other疯趟,調(diào)用other()方法,other掛載在全局函數(shù)window對象下谋梭,window對象下沒有userName 和 age 這兩個屬性信峻,所以輸出為undefined。第二段代碼瓮床,申明了data對象盹舞,包含了username和age屬性,一般情況下this指向它的調(diào)用者隘庄,data是selfIntroduction()的函數(shù)的調(diào)用者踢步,所以輸出了data的userName和age。
三丑掺、this作為事件觸發(fā)
? ? <div id="btn">請點(diǎn)擊</div>
? ? <script>
? ? const btn=document.getElementById('btn');
? ? ? ? btn.addEventListener('click',function () {
? ? ? ? ? ? console.log(this);?
? ? ? })
? ? </script>
? ? // 輸出? <div id="btn">請點(diǎn)擊</div>
小結(jié):這種情況下this指向了事件的事件源event获印。
四、構(gòu)造函數(shù)
const? fun=function(userName){
? ? ? ? this.userName=userName;
? ? }
? ? const? user=new fun('張三');? ?
? ? console.log(user.userName);? //張三
小結(jié):
new關(guān)鍵字構(gòu)造了一個對象實(shí)例街州,賦值給了user兼丰,所以userName就成為了user對象的屬性玻孟。
五、箭頭函數(shù)和this
const fun1=()=>{
? ? ? ? console.log(this);? //輸出 Window
? ? };
? ? fun1();
const data={
? ? ? ? userName:'張三',
? ? ? ? selfIntroduction:function(){
? ? ? ? ? ? console.log(this);? //輸出 Object {userName: "張三", selfIntroduction: function}
? ? ? ? ? ? const fun2=()=>{
? ? ? ? ? ? ? ? console.log(this);?
? ? ? ? ? ? ? ? //輸出 Object {userName: "張三", selfIntroduction: function}
? ? ? ? ? ? }
? ? ? ? ? ? fun2();
? ? ? ? }
? ? }
? ? data.selfIntroduction();
在箭頭函數(shù)中this指向創(chuàng)建者而不是調(diào)用者地粪,fun1在全局函數(shù)下創(chuàng)建取募,所以this指向window。
而fun2在對象data下創(chuàng)建蟆技,this指向data對象玩敏,所以在func2函數(shù)內(nèi)部this指向data對象,
es6的箭頭函數(shù)的this指向更加完善一些质礼。
?六旺聚、如何改變this的指向
最常見的用來改變this指向的函數(shù),包括call眶蕉、apply砰粹、bind
const func=function(){
? ? console.log(this);
};
func(); //window
func.apply({userName:"張三"}); //輸出 Object {userName: "張三"}
小結(jié):call、apply會將該方法綁定this之后立即執(zhí)行造挽,而bind方法會返回一個可執(zhí)行的函數(shù)碱璃。
七、總結(jié)
經(jīng)過以上的幾個案例饭入,可以總結(jié)出以下幾點(diǎn):
?1. 全局變量默認(rèn)掛載在window對象下嵌器;<br/>
2. 一般情況下this指向它的調(diào)用者;<br/>
3. es6的箭頭函數(shù)中谐丢,this指向創(chuàng)建者爽航,并非調(diào)用者;<br/>
4. 通過call乾忱、apply讥珍、bind可以改改變this的指向。
(PS:關(guān)于call窄瘟、apply衷佃、bind這三者之間的區(qū)別在我的其他博客里有專門的說明。)