本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰! javascript
使用 JavaScript 開發的時候,不少開發者多多少少會被 this 的指向搞蒙圈,可是實際上,關於 this 的指向,記住最核心的一句話:哪一個對象調用函數,函數裏面的 this 指向哪一個對象。前端
下面咱們針對這幾種狀況,舉例並說明原理:java
// 聲明位置
var test = function(){
console.log(this.x)
}
var x = "2";
var obj = {
x:"1",
fn:test,
}
// 調用位置
obj.fn(); // 1
test(); // 2
複製代碼
以上代碼,能夠看到,this 指向調用它所在方法的對象,test 方法在 obj 對象下,因此 this 指向 obj,test 在window 對象下,因此 this 指向 window。也能夠看出來:this和聲明位置無關,和調用位置有關。後端
可是下面這個狀況得注意數組
let obj1={
a:222
};
let obj2={
a:111,
fn:function(){
console.log(this.a);
}
}
obj1.fn = obj2.fn;
obj1.fn(); // 222
複製代碼
這個不難理解,雖然 obj1.fn 是從 obj2.fn 賦值而來,可是調用函數的是obj1,因此 this 指向 obj1。markdown
var a = 1;
function fn1(){
console.log(this.a); // 1
}
fn1();
window.b = 2;
function fn2(){
console.log(this.b); // 2
}
fn2();
//能夠理解爲 window.fn();
複製代碼
匿名函數,setTimeout:app
(function(){
console.log(this); // window
})();
setTimeout(() => {
console.log(this); // window
}, 0);
setTimeout(function(){
console.log(this); // window
}, 0);
複製代碼
var flag = undefined;
function Fn(){
flag = this;
}
var obj = new Fn();
console.log(flag === obj); // true
複製代碼
這個 this 指向 obj,內部原理仍是用 apply 把 this 指向obj的,回憶下JavaScript中 new 一個對象過程詳解。函數
call 和 apply 的做用,徹底同樣,惟一的區別:參數; call 接收的參數不固定,第一個參數是函數體內 this 的指向,第二個參數如下是依次傳入的參數。 apply接收兩個參數,第一個參數也是函數體內 this 的指向。第二個參數是一個集合對象(數組或者類數組)oop
var obj = {
name:'111',
getName:function(){
console.log(this.name)
}
};
var otherObj = {
name:'222',
};
var name = '333';
obj.getName(); // 111
obj.getName.call(); // 333
obj.getName.call(otherObj); // 222
obj.getName.apply(); // 333
obj.getName.apply(otherObj); // 222
obj.getName.bind(this)(); // 333
obj.getName.bind(otherObj)();// 222
複製代碼
關於 ES6 中的箭頭函數,官方的解釋是: 箭頭函數裏面的 this 是上下文( context ), 外部做用域的 this 就是箭頭函數內的 this。post
判斷箭頭函數的 this:
技巧:它的外層沒有函數,this 是 window;外層有函數,看外層函數的 this 是誰,它的 this 就是誰。
外層函數多是常規函數多是箭頭函數,判斷外層的 this 要根據函數種類用不一樣方法:
外層函數是常規函數就看外層函數是被誰調用的;
外層是箭頭函數就根據剛纔說的技巧來判斷;
let obj={
a:222,
fn:function(){
setTimeout(()=>{console.log(this.a)});
}
};
obj.fn(); // 222
複製代碼
var name = 'window';
var A = {
name: 'A',
sayHello: () => {
console.log(this.name)
}
}
A.sayHello(); // 輸出的是window,根據剛纔講的規則就能夠判斷
// 那如何改形成永遠綁定A呢:
var name = 'window';
var A = {
name: 'A',
sayHello: function(){
var s = () => console.log(this.name)
return s//返回箭頭函數s
}
}
var sayHello = A.sayHello();
sayHello();// 輸出A
複製代碼
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
var obj = {foo: foo};
console.log(foo.call(obj) === globalObject); // true
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
複製代碼
非嚴格模式下,this 默認指向全局對象 window;
// 非嚴格模式
function f1(){
return this;
}
console.log(f1() === window); // true
複製代碼
嚴格模式下, this 爲undefined;
// 嚴格模式
"use strict";
var fn2 = function(){
return this
}
console.log(fn2() == undefined); // true
複製代碼