this從入門到精通

this

按照慣例,先看一段代碼

看一段代碼

var name = "222";
var a = {
  name: "111",
  say: function () {
    console.log(this.name);
  },
};
var fun = a.say;
fun();
a.say();

var b = {
  name: "333",
  say: function (fn) {
    fun();
  },
};

b.say(a.say);
b.say = a.say;
b.say();

// 題目來(lái)源于網(wǎng)絡(luò) 并非自創(chuàng)

你能一眼看出輸出答案嗎纫谅?如果可以那么我相信 this 概念你已經(jīng)理解的很透徹了偎漫,如果你不懂輸出內(nèi)容,請(qǐng)接著向下看方篮,相信你會(huì)有所收獲

什么是 this

MDN 上是這樣說(shuō)的:在絕大多數(shù)情況下名秀,函數(shù)的調(diào)用方式?jīng)Q定了 this 的值

ECMAScript 規(guī)范中這樣寫:his 關(guān)鍵字執(zhí)行為當(dāng)前執(zhí)行環(huán)境的 ThisBinding。

按照自己的理解翻譯一下:在 JavaScript 中藕溅,this 的指向是調(diào)用時(shí)決定的匕得,而不是創(chuàng)建時(shí)決定的,這就會(huì)導(dǎo)致 this 的指向會(huì)讓人迷惑蜈垮,簡(jiǎn)單來(lái)說(shuō)耗跛,this 具有運(yùn)行期綁定的特性芒率。

調(diào)用位置

首先需要理解調(diào)用位置裹虫,調(diào)用位置就是函數(shù)在代碼中被調(diào)用的位置,而不是聲明的位置

function baz() {
  console.log("baz");
  bar();
}
function bar() {
  console.log("bar");
  foo();
}
function foo() {
  console.log("foo");
}
baz();
  • 對(duì)于 foo():調(diào)用位置是在 bar()中头镊。
  • 對(duì)于 bar():調(diào)用位置是在 baz()中惠猿。
  • 而對(duì)于 baz():調(diào)用位置是全局作用域中羔砾。

可以看出,調(diào)用位置應(yīng)該是當(dāng)前正在執(zhí)行的函數(shù)的前一個(gè)調(diào)用中

事件綁定

不論是 DOM0 還是 DOM2 事件綁定,給元素 e 的某個(gè)事件行為綁定方法姜凄,當(dāng)前事件觸發(fā)方法執(zhí)行政溃,方法種的 this 是當(dāng)前元素 e 本身

特殊情況:

  • IE6-8 基于 attachEvent 實(shí)現(xiàn) DOM2 事件綁定,事件觸發(fā)方法執(zhí)行态秧,方法中的 this 不是元素本身董虱,大部分情況是 window
  • 如果使用 call/apply/bind 強(qiáng)制改變 this 指向,我們以改變的為主

全局上下文 this

很好理解申鱼,全局上下文的 this 實(shí)際上就是 window

console.log(window === this); // true
var a = 1;
this.b = 2;
window.c = 3;
console.log(a + b + c); // 6

函數(shù)上下文 this

  • 普通函數(shù)
    普通函數(shù)執(zhí)行愤诱,看函數(shù)前面是否有點(diǎn)。有點(diǎn) 捐友,點(diǎn)前面是誰(shuí) this 就是誰(shuí)淫半,沒(méi)有點(diǎn) this 就是 window (嚴(yán)格模式是 undefined)

    fn() -> this: window/undefined
    obj.fn() -> this:obj
    xxx.proto.fn() -> this:xxx.proto

    自執(zhí)行函數(shù):this 一般是 window/undefined
    回調(diào)函數(shù)中的 this 一般也是 window/undefined

在函數(shù)內(nèi)部,this 的值取決于函數(shù)被調(diào)用的方式匣砖。

直接調(diào)用

this 指向全局變量科吭,如果當(dāng)前函數(shù)處于全局變量種

function foo() {
  return this;
}
console.log(foo() === window); // true

call()、apply()

this 指向綁定的對(duì)象

var person = {
  name: "axuebin",
  age: 25,
};
function say(job) {
  console.log(this.name + ":" + this.age + " " + job);
}
say.call(person, "FE"); // axuebin:25
say.apply(person, ["FE"]); // axuebin:25

可以看到猴鲫,定義了一個(gè) say 函數(shù)是用來(lái)輸出 name对人、age 和 job,其中本身沒(méi)有 name 和 age 屬性变隔,我們將這個(gè)函數(shù)綁定到 person 這個(gè)對(duì)象上规伐,輸出了本屬于 person 的屬性,說(shuō)明此時(shí) this 是指向?qū)ο?person 的匣缘。

bind()

this 將永久地被綁定到了 bind 的第一個(gè)參數(shù)猖闪。

作為對(duì)象的一個(gè)方法

this 指向調(diào)用函數(shù)的對(duì)象

var person = {
  name: "axuebin",
  getName: function () {
    return this.name;
  },
};
console.log(person.getName()); // axuebin

這里有一個(gè)需要注意的地方。肌厨。培慌。

var name = "xb";
var person = {
  name: "axuebin",
  getName: function () {
    return this.name;
  },
};
var getName = person.getName;
// getName 在全局環(huán)境中,此時(shí)this指向window 所以輸出 xb
console.log(getName()); // xb

發(fā)現(xiàn) this 又指向全局變量了柑爸,這是為什么呢吵护?

還是那句話,this 的指向得看函數(shù)調(diào)用時(shí)表鳍。

作為構(gòu)造函數(shù)

通過(guò)構(gòu)造函數(shù)創(chuàng)建一個(gè)對(duì)象其實(shí)執(zhí)行這樣幾個(gè)步驟:

  • 創(chuàng)建新對(duì)象
  • 將 this 指向這個(gè)對(duì)象
  • 給對(duì)象賦值(屬性馅而、方法)
  • 返回 this
  • 所以 this 就是指向創(chuàng)建的這個(gè)對(duì)象上。
function Person(name) {
  this.name = name;
  this.age = 25;
  this.say = function () {
    console.log(this.name + ":" + this.age);
  };
}
var person = new Person("axuebin");
console.log(person.name); // axuebin

箭頭函數(shù)

所有的箭頭函數(shù)都沒(méi)有 this,都是指向外層的當(dāng)前函數(shù)所在的上下文的 this

題解分析

看過(guò)上面的幾種 this 場(chǎng)景譬圣,對(duì)于開始的題目是不是豁然開朗了呢瓮恭,來(lái)分析一下

var name = "222";
var a = {
  name: "111",
  say: function () {
    console.log(this.name);
  },
};
var fun = a.say;
fun(); // 此時(shí)fun處于全局環(huán)境中,也就是全局環(huán)境調(diào)用這個(gè)方法厘熟,誰(shuí)調(diào)用this指向誰(shuí)屯蹦,所以打印 222
// fun() === fun.call(window)  fun相當(dāng)于是語(yǔ)法糖
a.say(); // 此時(shí)函數(shù)處于a對(duì)象中维哈,所以 this指向 a對(duì)象 所以打印 111
// a.say() === a.say.call(a)
var b = {
  name: "333",
  say: function (fn) {
    fn(); // 此時(shí)fn執(zhí)行沒(méi)有其他的this 綁定,
    // fn() === fn.call(window)
    // a.say() === fn() === fn.call(window) === a.say.call(window)
  },
};

b.say(a.say); // 打印 222
b.say = a.say;
// b.say = a.say 相當(dāng)于
// var b = {
//     name: '333',
//     say:function(){
//         console.log(this.name)
//     }
// }
b.say(); // 打印 333

ps: 有些內(nèi)容來(lái)源網(wǎng)絡(luò)登澜,忘記

最后結(jié)果: 222 111 222 333
看到這里阔挠,你明白 this 了嗎,不明白做點(diǎn)題目吧

this 相關(guān)面試題

第一題

let obj = {
    fn:(function(){
        return function(){
            console.log(this)
        }
    })()
}
obj.fn();
let fn = obj.fn;
fn();

第二題

var fullName = 'language';
var obj = {
    fullName: 'javascript',
    prop: {
        getFullName: function () {
            return this.fullName;
        }
    }
};
console.log(obj.prop.getFullName());
var test = obj.prop.getFullName;
console.log(test());

第三題

var name = 'window'; 
var Tom = {
    name: "Tom",
    show: function () {
        console.log(this.name);
    },
    wait: function () {
        var fun = this.show;
        fun();
    }
};
Tom.wait(); 

第四題

window.val = 1
var json = {
    val: 10,
    dbl: function () {
        this.val *= 2;
    }
}
json.dbl();
var dbl = json.dbl;
dbl();
json.dbl.call(window);
alert(window.val + json.val);

第五題

(function () {
    var val = 1; 
    var json = {
        val: 10,
        dbl: function () {
            val *= 2; 
        }
    };
    json.dbl();
    alert(json.val + val); 
})();

答案

// 第一題
obj.fn(); // this指向的是obj ,所以輸出 {fn:function(){}}
let fn = obj.fn;
fn();// 此時(shí)的fn 屬于全局脑蠕,相當(dāng)于把函數(shù)賦值給全局變量购撼,所以 this 是window

// 第二題
console.log(obj.prop.getFullName());
//=>this:obj.prop  =>obj.prop.fullName  =>undefined
var test = obj.prop.getFullName;
console.log(test());
//=>this:window =>window.fullName =>'language' */


// 第三題
var Tom = {
    name: "Tom",
    show: function () {
        // this->window
        console.log(this.name); //=>'window'
    },
    wait: function () {
        // this->Tom
        var fun = this.show;
        fun();
        // 此時(shí)fn執(zhí)行沒(méi)有其他的this 綁定,
       // fn() === fn.call(window)
    }
};

// 第四題
json.dbl();
//->this:json  ->json.val=json.val*2  ->json.val=20
var dbl = json.dbl;
dbl();
//->this:window ->window.val=window.val*2 ->window.val=2
json.dbl.call(window);
//->this:window ->window.val=window.val*2 ->window.val=4
alert(window.val + json.val); //=>"24"

// 第五題
(function () {
    var val = 1; //->2
    var json = {
        val: 10,
        dbl: function () {
            // this->json
            val *= 2; //val=val*2  此處的val是變量  json.val是對(duì)象的屬性
        }
    };
    json.dbl();
    alert(json.val + val); //=>"12"
})();
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谴仙,一起剝皮案震驚了整個(gè)濱河市份招,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狞甚,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件廓旬,死亡現(xiàn)場(chǎng)離奇詭異哼审,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)孕豹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門涩盾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人励背,你說(shuō)我怎么就攤上這事春霍。” “怎么了叶眉?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵址儒,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我衅疙,道長(zhǎng)莲趣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任饱溢,我火速辦了婚禮喧伞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绩郎。我一直安慰自己潘鲫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布肋杖。 她就那樣靜靜地躺著溉仑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪兽愤。 梳的紋絲不亂的頭發(fā)上彼念,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天挪圾,我揣著相機(jī)與錄音,去河邊找鬼逐沙。 笑死哲思,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吩案。 我是一名探鬼主播棚赔,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼徘郭!你這毒婦竟也來(lái)了靠益?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤残揉,失蹤者是張志新(化名)和其女友劉穎胧后,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抱环,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡壳快,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了镇草。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片眶痰。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖梯啤,靈堂內(nèi)的尸體忽然破棺而出竖伯,到底是詐尸還是另有隱情,我是刑警寧澤因宇,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布七婴,位于F島的核電站,受9級(jí)特大地震影響羽嫡,放射性物質(zhì)發(fā)生泄漏本姥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一杭棵、第九天 我趴在偏房一處隱蔽的房頂上張望婚惫。 院中可真熱鬧,春花似錦魂爪、人聲如沸先舷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蒋川。三九已至,卻和暖如春撩笆,著一層夾襖步出監(jiān)牢的瞬間捺球,已是汗流浹背缸浦。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留氮兵,地道東北人裂逐。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像泣栈,于是被迫代替她去往敵國(guó)和親卜高。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容