JavaScript中有幾種函數
1.使用function定義的函數
function foo(){
}
2.使用箭頭函數定義的函數
const foo=()=>{
}
3.在class中定義的函數
class A{
foo(){
}
}
4.生成器函數
function* foo(){
}
5.class定義的類,實際上也是函數
class Foo {
constructor(){
}
}
6、7、8異步函數
async function foo(){
}
const foo = async () => {
}
async function foo*(){
}
不同函數this關鍵字的行爲
function showThis(){
console.log(this);
}
var o = {
showThis: showThis
}
showThis(); // global
o.showThis(); // o
普通函數的 this 值由“調用它所使用的引用”決定,其中奧祕就在於:我們獲取函數的表達式,它實際上返回的並非函數本身,而是一個 Reference 類型。Reference 類型由兩部分組成:一個對象和一個屬性值。
不難理解 o.showThis 產生的 Reference 類型,即由對象 o 和屬性“showThis”構成。
當做一些算術運算(或者其他運算時),Reference 類型會被解引用,即獲取真正的值(被引用的內容)來參與運算,而類似函數調用、delete 等操作,都需要用到 Reference 類型中的對象。在這個例子中,Reference 類型中的對象被當作 this 值,傳入了執行函數時的上下文當中。
調用函數時使用的引用,決定了函數執行時刻的 this 值。
const showThis = () => {
console.log(this);
}
var o = {
showThis: showThis
}
showThis(); // global
o.showThis(); // global
我們看到,改爲箭頭函數後,不論用什麼引用來調用它,都不影響它的 this 值。
class C {
showThis() {
console.log(this);
}
}
var o = new C();
var showThis = o.showThis;
showThis(); // undefined
o.showThis(); // o
創建一個類並實例化以後再次調用獲得的結果又是不同的
this關鍵字的機制
JavaScript 標準定義了 [[thisMode]] 私有屬性。[[thisMode]] 私有屬性有三個取值。
- lexical:表示從上下文中找 this,這對應了箭頭函數。
- global:表示當 this 爲 undefined 時,取全局對象,對應了普通函數。
- strict:當嚴格模式時使用,this 嚴格按照調用時傳入的值,可能爲 null 或者 undefined。
class中的函數this行爲與其他函數不一樣正是因爲class設計成了默認爲strict模式執行。在strict模式下普通函數與class中的函數行爲一致。
"use strict"
function showThis(){
console.log(this);
}
var o = {
showThis: showThis
}
showThis(); // undefined
o.showThis(); // o
而箭頭函數中this的指向當前上下文中的this,所以下例中foo函數內部潛逃的剪頭函數this與foo相同,o.foo()中this爲對象o所以內部剪頭函數的this均爲o。
var o = {}
o.foo = function foo(){
console.log(this);
return () => {
console.log(this);
return () => console.log(this);
}
}
o.foo()()(); // o, o, o
操作this的內置函數
JavaScript中提供了apply call bind三個方法來改變函數中this的指向(不清楚用法自行百度)。三個方法只針對普通函數有效,箭頭函數、class均不會報錯,但是無法改變this,可以傳參。