js
的 this
是個比較令人頭疼的東西,尤其是在面試的時候凉馆,深受面試官的喜愛答憔。我們今天來談?wù)?js 中的 this
this 是什么裸诽,為什么要用 this
它是一個在每個函數(shù)作用域中自動定義的特殊標識符關(guān)鍵字, this
機制提供了更優(yōu)雅的方式來隱含地“傳遞”一個對象引用蹬竖,導致更加干凈的 API 設(shè)計和更容易的復(fù)用沼沈。當我們的代碼和使用環(huán)境約復(fù)雜,我們就越能感受到 this
的重要性
先看一段代碼
let x = {
num: 1,
sum: function(data) {
return this.num + data
}
}
let y = {
num: 1,
sum: function(data) {
return this.num + data
}
}
let y_sum = y.sum
console.log(x.sum(1)) // 2
console.log(y_sum(1)) // NaN
單從上面的代碼來看案腺,兩者似乎沒有區(qū)別庆冕,但是運行后的結(jié)果確是不一樣的
在看一段代碼
let x = {
num: 1,
sum: function(data) {
return this.num + data
}
}
let y = {
num: 1,
sum: data => {
return this.num + data
}
}
console.log(x.sum(1)) // 2
console.log(y.sum(1)) // NaN
也是一樣,看著倆段代碼差別不大劈榨,但是結(jié)果卻完全不一樣
var num = 2
var obj = {
num: 1,
say: function () {
setTimeout(function(){
console.log(this.num) // 2
}, 0)
}
}
obj.say()
一般函數(shù)的this
指向是指執(zhí)行該函數(shù)的運行對象
let x = {
num: 1,
sum: function(data) {
return this.num + data
// 這里的this是指運行了sum函數(shù)的x访递。所以this.num = 1
}
}
let y = {
num: 1,
sum: function(data) {
return this.num + data
// 由于這里運行sum函數(shù)的不再是y而是window。所以這里相當于window.num = undefined
}
}
let y_sum = y.sum
console.log(x.sum(1)) // 2
console.log(y_sum(1)) // NaN
箭頭函數(shù)的指向是指向運行該函數(shù)的父執(zhí)行上下文的this
,箭頭函數(shù)中的this
是在定義函數(shù)的時候綁定同辣,而不是在執(zhí)行函數(shù)的時候綁定拷姿。
let x = {
num: 1,
sum: function(data) {
return this.num + data
// 這里的this指的是x
}
}
let y = {
num: 1,
sum: data => {
return this.num + data
}
// 這里因為是箭頭函數(shù),所以這里的this在sum函數(shù)定義的時候就開始綁定了旱函,這里的this是window
}
console.log(x.sum(1)) // 2
console.log(y.sum(1)) // NaN
var obj = {
say: function () {
let _say = () => {
console.log(this);
// 這里的this就是say响巢,因為在定義_say時,_say會去拿父執(zhí)行上下文的this
}
return _say()
}
}
obj.say()
對于匿名函數(shù)來說棒妨,this的指向是window
var num = 2
var obj = {
num: 1,
say: function () {
setTimeout(function(){
console.log(this.num) // 2
// 這里的this是window
}, 0)
}
}
obj.say()
// 這里如果是箭頭函數(shù)踪古,結(jié)果又不一樣了
var obj2 = {
num: 1,
say: function () {
setTimeout(() =>{
console.log(this.num) // 1
}, 0)
}
}
obj2.say()
雖然有的時候,函數(shù)會在window下調(diào)用,this會指向window對象伏穆,但是this 不會以任何方式指向函數(shù)的 詞法作用域
function foo() {
var a = 2;
this.bar();
}
function bar() {
console.log( this.a );
}
foo(); //undefined
開發(fā)者試圖用 this 在 foo() 和 bar() 的詞法作用域間建立一座橋拘泞,使得bar() 可以訪問 foo()內(nèi)部作用域的變量 a。這樣的橋是不可能的枕扫。 你不能使用 this 引用在詞法作用域中查找東西陪腌。這是不可能的。
更多練習
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
// 這里最終調(diào)用foo函數(shù)的依然是obj2
function foo() {
console.log( this.a );
}
function doFoo(fn) {
// `fn` 只不過 `foo` 的另一個引用
// 在這里fn() != obj.foo()
fn();
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global";
doFoo( obj.foo ); // "oops, global"
var obj = {
say: function () {
function _say() {
// this 是什么烟瞧?想想為什么诗鸭?
console.log(this)
}
return _say.bind(obj)
}()
}
obj.say()
// 這里_say通過bind將this指向了obj,但是打印的結(jié)果卻還是window参滴,為什么呢强岸?
// 這里可以看作: 因為 = 賦值語句是由右向左運行的。所以這里的obj應(yīng)該是個undefined,所以this指向了window
換種寫法就會完全不一樣了
var obj = {}
obj.say: function () {
function _say() {
console.log(this)
}
return _say.bind(obj)
}()
obj.say()
// 這里this指向了obj