一直以來,對(duì)this的指向問題一直沒有好好理解沙热,最近得空叉钥,趕緊惡補(bǔ)一下。
1篙贸、涵義
this是什么投队?
簡(jiǎn)單說,關(guān)鍵字“this”指向當(dāng)前代碼運(yùn)行時(shí)的對(duì)象(當(dāng)前運(yùn)行時(shí)調(diào)用該屬性或方法的對(duì)象)
this是在函數(shù)調(diào)用過程中設(shè)置的
例子:
function fn() {
return this.name;
}
let a = {
name: '小明',
who: fn
}
let b = a.who;
console.log(a.who()); //this指向a爵川,當(dāng)前who方法是被a調(diào)用
console.log(b()); //this指向window敷鸦,當(dāng)前b處于全局環(huán)境下,this.b === window.b寝贡,所以this指向window
2扒披、this使用環(huán)境
全局上下文
在全局上下文環(huán)境中,this指向window對(duì)象
// 在瀏覽器中, window 對(duì)象同時(shí)也是全局對(duì)象:
console.log(this === window); // true
let a = 1;
console.log(window.a); //1
this.b = 2;
console.log(window.b); //2
console.log(b); //2
函數(shù)上下文
在函數(shù)內(nèi)部圃泡,this的值取決于函數(shù)被調(diào)用的方式碟案。
例子:
function fn() {
return this.name;
}
let a = {
name: '小明',
who: fn
}
let b = {
name: '小紅',
who: fn,
c: {
d: fn
}
}
console.log(a.who()); //this指向a
console.log(b.who()); //this指向b
console.log(fn()); //this指向window
console.log(b.c.d()); //this指向b.c,為什么不是指向b呢颇蜡?那是因?yàn)閠his總是指向直接調(diào)用它的最近的對(duì)象价说,this只會(huì)向上繼承最近的一層,不會(huì)繼承更上面的層风秤;
let h = b.c.d;
h(); //此時(shí)this指向window鳖目,因?yàn)閔處于全局對(duì)象中
再看一個(gè)例子:
let a = {
b () {
console.log(this);
let c = function () {
console.log(this);
}();
}
}
a.b();
這兩個(gè)this分別指向什么呢?
//第一個(gè)this指向a
//第二個(gè)this指向window
為什么會(huì)這樣呢缤弦?
就如開頭所說的:在函數(shù)內(nèi)部领迈,this的值取決于函數(shù)被調(diào)用的方式。
上面例子的函數(shù)可以看成如下的變體:
let d = function () {
console.log(this);
}
let a = {
b () {
console.log(this);
let c = d();//此時(shí),d相當(dāng)于是被window調(diào)用狸捅,所以this此時(shí)指向window
}
}
a.b();
那如果我們還是要堅(jiān)持第一種寫法衷蜓,那可以對(duì)this事先賦予一個(gè)變量來保存
let a = {
b () {
console.log(this);
let self = this;
let c = function () {
console.log(self);
}();
}
}
a.b(); //這樣this的值就不會(huì)被改變
箭頭函數(shù)下的this
let a = {
b () {
console.log(this);
let c = () => {
console.log(this);
};
return c;
}
}
a.b(); // 第一個(gè)this指向a
a.b()(); // 兩個(gè)this都指向a
//兩個(gè)this都綁定到a,這與非箭頭函數(shù)的綁定結(jié)果完成不一樣薪贫。
//這是因?yàn)楫?dāng)使用箭頭函數(shù)時(shí)恍箭,this自動(dòng)綁定到執(zhí)行上下文的外層函數(shù)上
let f = a.b;
f()(); //此時(shí)this指向window,因?yàn)閠his是在執(zhí)行的時(shí)候設(shè)置瞧省。這時(shí)候的f是被window調(diào)用扯夭,所以this指向window;
let f = a.b(); //此時(shí)鞍匾,this指向a交洗。a.b函數(shù)已經(jīng)被調(diào)用,所以this此時(shí)已經(jīng)綁定到a上橡淑;
f(); //此時(shí)的this綁定到哪里呢构拳?沒錯(cuò),還是在a上梁棠,這是因?yàn)榧^函數(shù)中this的值已經(jīng)被綁定到外層函數(shù)上置森。
this的綁定方法:call、apply符糊、bind
使用call凫海,或者apply方法可以指定this在執(zhí)行上下文的指向
call與apply的作用相同,它們的區(qū)別在于接受參數(shù)的方式不一樣男娄。call()接受的參數(shù)以列表的形式傳參行贪,而apply接受的參數(shù)以數(shù)組的方式傳參
例子:call、apply方法
function sum(b) {
return this.a + b;
}
let sum1 = {a: 1};
sum.call(sum1, 2); //3 this綁定到sum1
sum.apply(sum1, [2]); //3 this綁定到sum1
例子:bind方法
ES6新增了綁定this的bind()方法模闲,調(diào)動(dòng)fn.bind(obj)方法建瘫,會(huì)創(chuàng)建一個(gè)與fn具有相同函數(shù)體和作用域的函數(shù), 同時(shí)this將永久地被綁定到指定的obj對(duì)象上。
function fn() {
return this.a;
}
let obj = {
a: 'binded'
}
let bind1 = fn.bind(obj);
console.log(bind1()); //binded
let bind2 = bind1.bind({a: 'binded2'});
console.log(bind2); //binded
下面兩種環(huán)境中的this尸折,就是我們經(jīng)常使用的啰脚,略過啦
構(gòu)造函數(shù)中的this
構(gòu)造函數(shù)中的this指向new出來的對(duì)象(構(gòu)造的新對(duì)象)
事件處理函數(shù)中的this
當(dāng)函數(shù)被用作事件處理函數(shù)時(shí),this指向當(dāng)前觸發(fā)的DOM對(duì)象
例子:
<button onclick="alert(this.tagName)">
Show this
</button>
// this指向當(dāng)前target:button元素