一篇文章詳細(xì)講解JavaScript中的this(普通函數(shù)、箭頭函數(shù)、?函數(shù)運(yùn)用)
前言
this對(duì)象:解析器在每次調(diào)用函數(shù)時(shí),都會(huì)向函數(shù)內(nèi)部轉(zhuǎn)遞一個(gè)隱含的參數(shù),這個(gè)參數(shù)就是this,this指向的是一個(gè)對(duì)象,這個(gè)對(duì)象我們稱為函數(shù)執(zhí)行的上下文對(duì)象,根據(jù)函數(shù)調(diào)用方式的不同,this會(huì)指向不同的對(duì)象
一、將根據(jù)一下幾個(gè)方面介紹this的指向問題
- 全局環(huán)境中的 this
- 函數(shù)中的 this
- 對(duì)象方法中的 this
- 構(gòu)造函數(shù)中的 this
- 事件處理函數(shù)中的 this
- 箭頭函數(shù)中的 this
1、全局環(huán)境中的this
在全局環(huán)境中(不在任何函數(shù)或?qū)ο髢?nèi)部),this指向全局對(duì)象(在瀏覽器環(huán)境中是window,在node.js中是global)
console.log(this === window); // 在瀏覽器中輸出 true
2、函數(shù)中的this
當(dāng)一個(gè)函數(shù)被直接調(diào)用時(shí),this在非嚴(yán)格模式下指向全局對(duì)象(window),在嚴(yán)格模式下指向undefined
JS嚴(yán)格模式:JavaScript在語法和行為上存在一些模糊的特性,可能導(dǎo)致一些不易察覺的錯(cuò)誤,為提高代碼的質(zhì)量和可維護(hù)性,js引入了嚴(yán)格模式,通過啟用一些額外的規(guī)則,強(qiáng)制執(zhí)行更嚴(yán)格的語法和行為。在嚴(yán)格模式下代碼中的潛在問題將被捕獲并拋出錯(cuò)誤,有助于提前發(fā)現(xiàn)和修復(fù)潛在bug。
function regularFunction() {
console.log(this);
}
regularFunction(); // 非嚴(yán)格模式下指向 window,嚴(yán)格模式下為 undefined
// 演示嚴(yán)格模式下的情況
(function () {
"use strict";
regularFunction();
})();
3、對(duì)象方法中的this
當(dāng)函數(shù)作為對(duì)象的方法被調(diào)用時(shí),this指向調(diào)用該方法的對(duì)象
var person = {
name: "John",
sayName: function () {
console.log(this.name);
}
};
person.sayName(); // 輸出 "John",這里的 this 指向 person 對(duì)象
4、構(gòu)造函數(shù)中的this
使用new關(guān)鍵字(實(shí)例化)調(diào)用函數(shù)時(shí),該函數(shù)被當(dāng)作構(gòu)造函數(shù)(類),this會(huì)指向新創(chuàng)建的對(duì)象實(shí)例
function Person(name) {
this.name = name;
this.sayHello = function () {
console.log("Hello, I'm " + this.name);
};
}
var john = new Person("John");
john.sayHello(); // 輸出 "Hello, I'm John",這里 this 指向 john 實(shí)例
構(gòu)造函數(shù)怎么執(zhí)行創(chuàng)建對(duì)象的過程:
- 調(diào)用一個(gè)構(gòu)造函數(shù),他會(huì)立即創(chuàng)建一個(gè)對(duì)象
- 將新建的對(duì)象設(shè)置為函數(shù)中的this,在構(gòu)造函數(shù)中可以使用this來引用新建的對(duì)象
- 逐行執(zhí)行函數(shù)中的代碼
- 將新建的對(duì)象作為返回值返回
在構(gòu)造函數(shù)中,創(chuàng)建對(duì)象和返回對(duì)象都給我們隱藏了,使用同一個(gè)構(gòu)造函數(shù)創(chuàng)建的對(duì)象,我們稱為一類對(duì)象,也將一個(gè)構(gòu)造函數(shù)稱為一個(gè)類。我們將通過一個(gè)構(gòu)造函數(shù)創(chuàng)建的對(duì)象,稱為是該類的實(shí)例。
5、事件處理函數(shù)中的this
在DOM事件處理函數(shù)中,this通常指向觸發(fā)事件的元素。
<button id="myButton">Click me</button>
<script>
var button = document.getElementById("myButton");
button.onclick = function () {
console.log(this); // 點(diǎn)擊按鈕時(shí),這里的 this 指向按鈕元素
//打印 :<button id="myButton">Click me</button>
};
</script>
7、箭頭函數(shù)中的this
箭頭函數(shù)沒有自己的this,它的this繼承自外層作用域的this
// 普通函數(shù)
function outerFunction() {
this.name = "Outer";
var innerFunction = function () {
console.log(this.name);
};
innerFunction();
}
// 箭頭函數(shù)
function outerFunctionWithArrow() {
this.name = "Outer with Arrow";
var innerFunction = () => {
console.log(this.name);
};
innerFunction();
}
new outerFunction(); // 輸出 undefined,因?yàn)?innerFunction 中的 this 指向全局對(duì)象,全局對(duì)象沒有 name 屬性
new outerFunctionWithArrow(); // 輸出 "Outer with Arrow",箭頭函數(shù)的 this 繼承自 outerFunctionWithArrow 的 this
二、改變this指向的方法
由于箭頭函數(shù)的this來自于繼承,箭頭函數(shù)無法使用以下三種方法改變this指向
1、call()方法
call方法是附加在函數(shù)調(diào)用后面使用,可以忽略函數(shù)本身的 this 指向- 語法: 函數(shù)名.call(要改變的 this 指向,要給函數(shù)傳遞的參數(shù)1,要給函數(shù)傳遞的參數(shù)2, ...)
- 使用 call 方法的時(shí)候:
1、會(huì)立即執(zhí)行函數(shù)
2、第一個(gè)參數(shù)是你要改變的函數(shù)內(nèi)部的 this 指向
3、第二個(gè)參數(shù)開始,依次是向函數(shù)傳遞參數(shù)
var obj = { name: 'Jack' }
function fn(a, b) {
console.log(this)
console.log(a)
console.log(b)
}
fn(1, 2)
fn.call(obj, 1, 2)
fn(1,2)的時(shí)候,函數(shù)內(nèi)部的 this 指向 window(函數(shù)被直接調(diào)用)fn.call(obj, 1, 2)的時(shí)候,函數(shù)內(nèi)部的 this 就指向了 obj 這個(gè)對(duì)象
2、apply()方法
apply方法是附加在函數(shù)調(diào)用后面使用,可以忽略函數(shù)本身的 this 指向- 語法: 函數(shù)名.apply(要改變的 this 指向,[要給函數(shù)傳遞的參數(shù)1, 要給函數(shù)傳遞的參數(shù)2, ...])
- 使用 call 方法的時(shí)候:
1、會(huì)立即執(zhí)行函數(shù)
2、第一個(gè)參數(shù)是你要改變的函數(shù)內(nèi)部的 this 指向
3、第二個(gè)參數(shù)是一個(gè) 數(shù)組,數(shù)組里面的每一項(xiàng)依次是向函數(shù)傳遞的參數(shù)(和call方法的主要區(qū)別點(diǎn))
var obj = { name: 'Jack' }
function fn(a, b) {
console.log(this)
console.log(a)
console.log(b)
}
fn(1, 2)
fn.apply(obj, [1, 2])
fn(1,2)的時(shí)候,函數(shù)內(nèi)部的 this 指向 window(函數(shù)被直接調(diào)用)fn.call(obj, 1, 2)的時(shí)候,函數(shù)內(nèi)部的 this 就指向了 obj 這個(gè)對(duì)象
3、bind()方法
bind方法是附加在函數(shù)調(diào)用后面使用,可以忽略函數(shù)本身的 this 指向- 和 call / apply 有一些不一樣,就是不會(huì)立即執(zhí)行函數(shù),而是返回一個(gè)已經(jīng)改變了 this 指向的函數(shù)
- 語法: var newFn = 函數(shù)名.bind(要改變的 this 指向); newFn(傳遞參數(shù))
var obj = { name: 'Jack' }
function fn(a, b) {
console.log(this)
console.log(a)
console.log(b)
}
fn(1, 2)
var newFn = fn.bind(obj)
newFn(1, 2)
- bind 調(diào)用的時(shí)候,不會(huì)執(zhí)行 fn 這個(gè)函數(shù),而是返回一個(gè)新的函數(shù)
- 這個(gè)新的函數(shù)就是一個(gè)改變了 this 指向以后的 fn 函數(shù)
fn(1, 2)的時(shí)候 this 指向 windownewFn(1, 2)的時(shí)候執(zhí)行的是一個(gè)和 fn 一摸一樣的函數(shù),只不過里面的 this 指向改成了 obj
三、回調(diào)函數(shù)中this指向
這里我們補(bǔ)充一下在回調(diào)函數(shù)運(yùn)用中this指向(也是容易混淆的知識(shí)點(diǎn))
1、對(duì)象方法作為回調(diào)函數(shù)
如果回調(diào)函數(shù)是一個(gè)對(duì)象的方法,并且是以對(duì)象方法的方式傳遞進(jìn)去的,那么 this 通常會(huì)指向該對(duì)象。
var myObject = {
value: 10,
callbackFunction: function () {
console.log(this.value);
}
};
[1,2,3].forEach(() => {
myObject.callbackFunction()
}); //輸出三個(gè)10
在這個(gè)例子中,forEach 是數(shù)組的方法,myObject.callbackFunction 作為回調(diào)函數(shù)傳遞給 forEach。當(dāng) forEach 調(diào)用這個(gè)回調(diào)函數(shù)時(shí),this 仍然指向 myObject,因?yàn)檫@個(gè)函數(shù)本質(zhì)上還是 myObject 的一個(gè)方法。
2、箭頭函數(shù)作為回調(diào)函數(shù)
箭頭函數(shù)沒有自己的 this,它會(huì)繼承外層作用域的 this(依據(jù)詞法作用域規(guī)則)。
function outerFunction() {
this.name = "Outer";
var array = [1, 2, 3];
array.forEach(() => {
console.log(this.name); //打印三次Outer
});
}
new outerFunction();
根據(jù)上面兩個(gè)例子,這里我們介紹一下普通函數(shù)和箭頭函數(shù)在確定this指向時(shí)的一些區(qū)別:
1、普通函數(shù)
普通函數(shù)在函數(shù)定義時(shí)會(huì)確定函數(shù)的作用域,但不會(huì)明確函數(shù)中this的指向。普通函數(shù)中this的指向是在函數(shù)被調(diào)用時(shí)被確定(指向調(diào)用者或者全局對(duì)象)
2、箭頭函數(shù)
箭頭函數(shù)由于其本身不會(huì)生成this,其this繼承自外層作用域。箭頭函數(shù)在定義時(shí)不僅會(huì)確定作用域,而且會(huì)捕獲外層作用域的this作為自身的this,箭頭函數(shù)的this在定義時(shí)就已經(jīng)確定,在其后的函數(shù)調(diào)用時(shí),無論調(diào)用箭頭函數(shù)的是誰它的this指向都不會(huì)發(fā)生改變。
以上面這個(gè)例子為例:
箭頭函數(shù)定義在 outerFunction 這個(gè)函數(shù)內(nèi)部,注意不是定義在 forEach 方法內(nèi)。具體可以了解一下函數(shù)傳參的步驟,這里箭頭函數(shù)是先在 outerFunction 這個(gè)函數(shù)內(nèi)部定義,之后才作為參數(shù)傳給 forEach 方法。箭頭函數(shù)繼承了 outerFunction 函數(shù)的this,并在之后被 forEach 方法調(diào)用時(shí)不會(huì)發(fā)生改變。
3、回調(diào)函數(shù)指向全局對(duì)象的常見情況
當(dāng)普通函數(shù)作為回調(diào)函數(shù),并且這個(gè)普通函數(shù)是被一個(gè)全局函數(shù)(如 setTimeout、setInterval)或者在全局作用域中獨(dú)立調(diào)用的函數(shù)(沒有通過對(duì)象來調(diào)用)調(diào)用時(shí),在非嚴(yán)格模式下,this 通常會(huì)指向全局對(duì)象。
//被一個(gè)全局函數(shù)調(diào)用
setTimeout(function () {
console.log(this);
}, 1000);
//在全局作用域中獨(dú)立調(diào)用
function outer(){
inner()
}
function inner(){
console.log(this);
}
outer()
四、總結(jié)與常見錯(cuò)誤示例
this指向:1、普通函數(shù):誰調(diào)用函數(shù),this就指向誰,沒有調(diào)用者就指向全局對(duì)象Window
2、箭頭函數(shù):箭頭函數(shù)不會(huì)創(chuàng)建this,它的this繼承自上層作用域中的this
1、案例一
//回調(diào)函數(shù)中錯(cuò)誤使用this
var person = {
name: "Eve",
greetLater: function () {
setTimeout(function () {
console.log(this.name); // 此處的function為普通函數(shù),作為setTimeout的參數(shù)this指向全局對(duì)象
}, 1000);
}
};
person.greetLater();
此處的function為普通函數(shù),被一個(gè)全局函數(shù)調(diào)用,其this指向全局對(duì)象 Window 。
要想輸出 Eve ,將此處的普通函數(shù)改為箭頭函數(shù)即可。
var person = {
name: "Eve",
greetLater: function () {
setTimeout( ()=> {
console.log(this.name); // 輸出Eve
}, 1000);
}
};
person.greetLater();
2、案例二
//在嵌套函數(shù)中混淆 this 指向
var outer = {
name: "Outer Object",
innerFunction: function () {
var inner = {
name: "Inner Object",
nestedFunction: function () {
console.log(this.name); // 這里 this 指向 inner,而不是 outer
}
};
inner.nestedFunction();
}
};
outer.innerFunction();
nestedFunction 是作為 inner 對(duì)象的方法被調(diào)用,this指向 inner 對(duì)象(根據(jù)普通函數(shù) this 指向的規(guī)則,當(dāng)函數(shù)作為對(duì)象的方法被調(diào)用時(shí),this 會(huì)指向調(diào)用該函數(shù)的對(duì)象。)
4.2.1、使用外層作用域this的方法
想要訪問到 outer 對(duì)象的 name 屬性,可以使用以下兩種方法:
1、保存外層 this 的引用
var outer = {
name: "Outer Object",
innerFunction: function () {
var self = this;
var inner = {
name: "Inner Object",
nestedFunction: function () {
console.log(self.name); // 現(xiàn)在可以訪問到 outer 的 name 屬性,輸出 "Outer Object"
}
};
inner.nestedFunction();
}
};
outer.innerFunction();
在方法的開頭先把 this 保存到一個(gè)變量中(通常命名為 self 或 that 等),然后在 inner 對(duì)象中使用這個(gè)保存的變量來訪問 outer 對(duì)象的屬性。
2、使用箭頭函數(shù)
var outer = {
name: "Outer Object",
innerFunction: function () {
var inner = {
name: "Inner Object",
nestedFunction: () => {
console.log(this.name); // 輸出 "Outer Object"
}
};
inner.nestedFunction();
}
};
outer.innerFunction();
將 nestedFunction 改為箭頭函數(shù),因?yàn)榧^函數(shù)會(huì)繼承外層作用域的 this,在這里外層作用域是 outer.innerFunction(),其 this 指向 outer 對(duì)象,所以箭頭函數(shù)里的 this 也能指向 outer 對(duì)象。
總結(jié)
到此這篇關(guān)于JavaScript中this(普通函數(shù)、箭頭函數(shù)、 函數(shù)運(yùn)用)的文章就介紹到這了,更多相關(guān)JS中this普通函數(shù)、箭頭函數(shù)、回調(diào)函數(shù)運(yùn)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用 Jest 和 Supertest 進(jìn)行接口端點(diǎn)測試實(shí)例詳解
這篇文章主要介紹了使用 Jest 和 Supertest 進(jìn)行接口端點(diǎn)測試,結(jié)合實(shí)例形式詳細(xì)分析了使用 Jest 和 Supertest 進(jìn)行接口端點(diǎn)測試具體原理、操作技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-04-04
js綜合應(yīng)用實(shí)例簡單的表格統(tǒng)計(jì)
在做調(diào)查問卷的過程中,遇到一個(gè)表格的統(tǒng)計(jì)問題,一個(gè)需要用到j(luò)s方面的綜合知識(shí),感覺還不錯(cuò)所以記錄下來與大家分享,感興趣的朋友可以了解下2013-09-09

