JS中this關(guān)鍵字詳解

1、JS中函數(shù)的幾種調(diào)用方式

(1)普通函數(shù)調(diào)用
(2)作為對象方法調(diào)用
(3)作為構(gòu)造函數(shù)調(diào)用
(4)apply/call方法調(diào)用
(5)Function.ptototype.bind()方法
(6)ES6箭頭函數(shù)
總之:無論誰調(diào)用這個函數(shù)或方法this就指向誰

2伤柄、調(diào)用方式實(shí)例與解析

(1)普通函數(shù)調(diào)用

function person(){
    this.name="hello";
    console.log(this);       // window
    console.log(this.name);     // hello
}
person();

解析:person函數(shù)作為普通函數(shù)調(diào)用累榜,實(shí)際上person是作為window全局對象的一個方法進(jìn)行調(diào)用的逻恐,即window.person()遭居,所以window對象調(diào)用了person方法刽辙,那么person函數(shù)中的this就指向window但狭,同事window還擁有了另外一個屬性name披诗,值為hello

(2)作為對象方法調(diào)用

var name = "HELLO";
var person = {
    name:"hello",
    showName:function(){
        console.log(this.name);
    }
}
foo.showName();      //這里是person對象調(diào)用showName方法,很顯然this關(guān)鍵字是指向person對象的立磁,因此輸出hello
var showNameA = person.showName;
showNameA();     //這里將person.showName方法賦給showNameA變量呈队,此時showNameA變量相當(dāng)于window對象的一個屬性,因此showNameA()執(zhí)行的時候相當(dāng)于window.showNameA()唱歧,即window對象調(diào)用showNameA這個方法宪摧,所以this關(guān)鍵字指向window,因此輸出HELLO
var personA = {
    name: "hello",
    showName: function(){
        console.log(this.name);     // HELLO
    }
}
var personB = {
    name: "HELLO",
    sayName: personA.showName
}
personB.sayName();  //雖然showName方法是在personA這個對象中定義颅崩,但是調(diào)用的時候卻是在personB這個對象中調(diào)用几于,因此this對象指向personB,因此輸出HELLO

(3)作為構(gòu)造函數(shù)調(diào)用

function Person(name){
    this.name = name;
}
var personA = Person("hello");  
console.log(window.name);     //此處沒有進(jìn)行new操作沿后,相當(dāng)于window對象調(diào)用Person("hello")方法沿彭,此時this指向window對象,并進(jìn)行賦值操作window.name = "hello"
var personB = new Person("hello");
console.log(personB.name);     // hello
function person(name){//new操作符(實(shí)例化對象)的內(nèi)部過程
    var o = {};
    o.__proto__ = Person.prototype;  //原型繼承
    Person.call(o,name);
    return o;
}
var personB = person("hello");
console.log(personB.name);  //hello  

解析:在person里面首先創(chuàng)建一個空對象o尖滚,將o的proto指向Person.prototype完成對原型的屬性和方法的繼承喉刘;Person.call(o,name)這里即函數(shù)Person作為apply/call調(diào)用(具體內(nèi)容下方)瞧柔,將Person對象里的this改為o,即完成了o.name=name操作睦裳;返回對象o造锅;因此 person("hello") 返回了一個繼承了Person.prototype 對象上的屬性和方法,以及擁有 name 屬性為"hello"的對象推沸,并將它賦給變量personB备绽,所以 console.log(personB.name) 會輸出 hello

(4)apply/call方法調(diào)用:在JS里函數(shù)也是對象,因此函數(shù)也有方法鬓催。從Function.prototype上繼承了Function.prototype.call/Function.prototype.apply方法肺素,call/apply方法最大的作用就是能改變this關(guān)鍵字的指向

var name="HELLO";
var Person={
    name: "hello",
    showName: function(){
        console.log(this.name);
    }
}
Person.showName.call(); //call方法里面的第一個參數(shù)為空,默認(rèn)指向window宇驾。雖然showName方法定義在Person對象里面倍靡,但是使用call方法后,將showName方法里面的this指向了window课舍。因此輸出"HELLO";
function FruitA(n1, n2){
    this.n1 = n1;
    this.n2 = n2;
    this.change = function(x,y){
        this.n1 = x;
        this.n2 = y;
    }
}
var fruitA = new FruitA("cheery","banana");
var FruitB = {
    n1: "apple",
    n2: "orange"
};
fruitA.change.call(FruitB,"pear","peach");
console.log(FruitB.n1);      //FruitB調(diào)用fruitA的change方法塌西,將fruitA中的this綁定到對象FruitB上,因此輸出pear
console.log(FruitB.n2);     //FruitB調(diào)用fruitA的change方法筝尾,將fruitA中的this綁定到對象FruitB上捡需,因此輸出peach

(5)Function.ptototype.bind()方法

var name = "HELLO";
function Person(name){
    this.name = name;
    this.sayName = function(){
        setTimeout(function(){
            console.log("my name is "+this.name);
        },50)
    }
}
var person = new Person("hello");
person.sayName()     //setTimeout()定時函數(shù)相當(dāng)于window.setTimeout(),由window這個全局對象對調(diào)用筹淫,因此this的指向?yàn)閣indow,站辉,則this.name則為 HELLO
var name = "HELLO";
function Person(name){
    this.name = name;
    this.sayName = function(){
        setTimeout(function(){
            console.log("my name is "+this.name);
        }.bind(this),50)  //注意這個地方使用的bind()方法,綁定setTimeout里面的匿名函數(shù)的this一直指向Person對象
    }
}
var person = new Person("xl");
person.sayName();     //setTimeout(function(){console.log(this.name)}.bind(this),50);损姜,匿名函數(shù)使用bind(this)方法后創(chuàng)建了新的函數(shù)饰剥,這個新的函數(shù)不管在什么地方執(zhí)行,this都指向的Person摧阅,而非window汰蓉,因此最后的輸出為"my name is hello"而不是"my name is HELLO"

解析:setTimeout/setInterval 匿名函數(shù)執(zhí)行的時候,this默認(rèn)指向window對象棒卷,除非手動改變this的指向顾孽。在《javascript高級程序設(shè)計(jì)》當(dāng)中,寫到:“超時調(diào)用的代碼(setTimeout)都是在全局作用域中執(zhí)行的娇跟,因此函數(shù)中的this的值岩齿,在非嚴(yán)格模式下是指向window對象,在嚴(yán)格模式下是指向undefined”苞俘。

var name = "HELLO";
function Person(){
    this.name = "hello";
    this.showName = function(){
        console.log(this.name);
    }
    setTimeout(this.showName,50);
}
var person = new Person();      //在setTimeout(this.showName,50)語句中,會延時執(zhí)行this.showName方法龄章,this.showName方法即構(gòu)造函數(shù)Person()里面定義的方法吃谣。50ms后乞封,執(zhí)行this.showName方法,this.showName里面的this此時便指向了window對象岗憋,因此輸出 HELLO
var name = "HELLO";
function Person(){
    this.name = "hello";
    var that = this;
    this.showName = function(){
        console.log(that.name);
    }
    setTimeout(this.showName,50)
}
var person=new Person();     //在Person函數(shù)當(dāng)中將this賦值給that肃晚,即讓that保存Person對象,因此在setTimeout(this.showName,50)執(zhí)行過程當(dāng)中console.log(that.name)會輸出Person對象的屬性hello
var name = "HELLO";
var person = {
    name: "hello",
    showName: function(){
        console.log(this.name);
    },
    sayName: function(){
        (function(callback){
            callback();
        })(this.showName)
    }
}
person.sayName();     //匿名函數(shù)的執(zhí)行同樣在默認(rèn)情況下this是指向window的仔戈,除非手動改變this的綁定對象关串,因此輸出 HELLO

(6)Eval函數(shù):該函數(shù)執(zhí)行的時候,this綁定到當(dāng)前作用域的對象上

var name = "HELLO";
var person = {
    name: "hello",
    showName: function(){
        eval("console.log(this.name)");
    }
}
person.showName();     //hello
var a = person.showName;
a();     // HELLO

(7)箭頭函數(shù):ES6里面this指向固定化监徘,始終指向外部對象晋修,因?yàn)榧^函數(shù)沒有this,因此它自身不能進(jìn)行new實(shí)例化凰盔,同時也不能使用call, apply, bind等方法來改變this的指向

function Timer() {
    this.seconds = 0;
    setInterval( () => this.seconds ++, 1000);
} 
var timer = new Timer();
setTimeout( () => console.log(timer.seconds), 3100);     //構(gòu)造函數(shù)內(nèi)部的setInterval()內(nèi)的回調(diào)函數(shù)墓卦,this始終指向?qū)嵗膶ο螅@取實(shí)例化對象的seconds的屬性户敬,每1s這個屬性的值都會增加1落剪,因此最后輸出 3
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市尿庐,隨后出現(xiàn)的幾起案子忠怖,更是在濱河造成了極大的恐慌,老刑警劉巖抄瑟,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凡泣,死亡現(xiàn)場離奇詭異,居然都是意外死亡锐借,警方通過查閱死者的電腦和手機(jī)问麸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钞翔,“玉大人严卖,你說我怎么就攤上這事〔冀危” “怎么了哮笆?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長汰扭。 經(jīng)常有香客問我稠肘,道長,這世上最難降的妖魔是什么萝毛? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任项阴,我火速辦了婚禮,結(jié)果婚禮上笆包,老公的妹妹穿的比我還像新娘环揽。我一直安慰自己略荡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布歉胶。 她就那樣靜靜地躺著汛兜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪通今。 梳的紋絲不亂的頭發(fā)上粥谬,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機(jī)與錄音辫塌,去河邊找鬼漏策。 笑死,一個胖子當(dāng)著我的面吹牛璃氢,可吹牛的內(nèi)容都是我干的哟玷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼一也,長吁一口氣:“原來是場噩夢啊……” “哼巢寡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起椰苟,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤抑月,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后舆蝴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谦絮,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年洁仗,在試婚紗的時候發(fā)現(xiàn)自己被綠了层皱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡赠潦,死狀恐怖叫胖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情她奥,我是刑警寧澤瓮增,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站哩俭,受9級特大地震影響绷跑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜凡资,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一砸捏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦带膜、人聲如沸吩谦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至咐扭,卻和暖如春芭挽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蝗肪。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工袜爪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人薛闪。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓辛馆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親豁延。 傳聞我的和親對象是個殘疾皇子昙篙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354