[英]Function returning a function doesn’t throw an error despite the argument being undefined
我在一個教程中看到了這段代碼片段:
const myFunction = () => {
return function (caller) {
caller(firstFuctnion());
caller(secondFunction());
};
};
你能告訴我它是如何工作的,一旦我這樣稱呼它:
myFunction()
當caller
參數實際上沒有定義時,為什么我沒有收到錯誤?
另一方面,如果我省略它並編寫如下代碼:
const myFunction = () => {
return function () {
firstFuctnion();
secondFunction();
};
};
這兩個函數firstFuction()
和secondFunction()
沒有被執行。 那么,那個caller
——或者不管它叫什么——究竟是如何工作的呢?
對於那些可能想要查看整個功能代碼的人:
const redux = require("redux"); const thunkMiddleware = require("redux-thunk").default; const axios = require("axios"); const createStore = redux.createStore; const applyMiddleware = redux.applyMiddleware; const initialState = { loading: false, users: [], error: "", }; const FETCH_USERS_REQUEST = "FETCH_USERS_REQUEST"; const FETCH_USERS_SUCCESS = "FETCH_USERS_SUCCESS"; const FETCH_USERS_FAILURE = "FETCH_USERS_FAILURE"; const fetchUsersRequest = () => { return { type: FETCH_USERS_REQUEST, }; }; const fetchUsersSuccess = (users) => { return { type: FETCH_USERS_SUCCESS, payload: users, }; }; const fetchUsersFailure = (error) => { return { type: FETCH_USERS_FAILURE, payload: error, }; }; const fetchUsers = () => { return function (dispatch) { dispatch(fetchUsersRequest()); axios.get("https://jsonplaceholder.typicode.com/users").then((response) => { // response.data is the users const users = response.data.map((user) => user.id); dispatch(fetchUsersSuccess(users)); }).catch((error) => { // error.message is the error message dispatch(fetchUsersFailure(error.message)); }); }; }; const reducer = (state = initialState, action) => { console.log(action.type); switch (action.type) { case FETCH_USERS_REQUEST: return {...state, loading: true, }; case FETCH_USERS_SUCCESS: return { loading: false, users: action.payload, error: "", }; case FETCH_USERS_FAILURE: return { loading: false, users: [], error: action.payload, }; } }; const store = createStore(reducer, applyMiddleware(thunkMiddleware)); store.subscribe(() => { console.log(store.getState()); }); store.dispatch(fetchUsers());
我不明白這部分。 該dispatch
實際上做了什么。 它沒有作為參數傳遞,也沒有在任何地方定義它是什么。 是function嗎? 我可以在那里寫whatever
。
const fetchUsers = () => {
return function (dispatch) {
dispatch(fetchUsersRequest());
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((response) => {
// response.data is the users
const users = response.data.map((user) => user.id);
dispatch(fetchUsersSuccess(users));
})
.catch((error) => {
// error.message is the error message
dispatch(fetchUsersFailure(error.message));
});
}; };
函數被視為任何其他值,這意味着它們可以從函數返回。 調用myFunction
將簡單地返回內部 function,這將需要在調用它自己時將參數caller
傳遞給它。
內部 function 將記住任何傳遞給它的 arguments 的封閉 function。
我用來理解這個概念的一個例子是“乘法器工廠”function
const answer = function() { console.log("The answer is: "); } const multiplier = function(factor) { return function(n){ answer(); console.log( n * factor); }; } const twice = multiplier(2); const triple = multiplier(3); twice(4); // The answer is: 8 triple(5); // The answer is: 15
在上面的代碼中, twice
和triple
基本上如下
const twice = function(n) { console.log("The answer is: "); console.log(n * 2); } const triple = function(n) { console.log("The answer is: "); console.log(n * 3); } twice(4); // The answer is: 8 triple(5); // The answer is: 15
要了解有關這些概念的更多信息,我建議閱讀 Javascript 中的“高階函數”和“閉包”
讓我們考慮一下這段代碼的簡化版本。 在您為您的問題添加一些重要的上下文之前(事實上myFunction()
正在被使用,以及它是如何使用的),我不太確定您的困惑在哪里,所以這個答案從回調的一般解釋開始,更高階函數和柯里化。
首先,讓我們把function
變成一個箭頭 function,這樣代碼讀起來更直接。 它們之間存在差異,但現在讓我們忽略它們。 讓我們也將myFunction
重命名為 external ,這樣我們就知道我們在談論哪個outer
。
const outer = () => {
return (caller) => {
caller(something);
};
};
outer
是 function。 outer()
也是一個 function; 這意味着,function outer
的返回值本身就是 function。
由於outer
是返回 function 的 function ,這使得outer
成為高階 function (HOF) (根據 HOF 的兩個定義之一)
明確地說,您可以使用另一個變量引用返回的 function:
const inner = outer();
當
caller
參數實際上沒有定義時,為什么我沒有收到錯誤?
這是一個奇怪的問題。 當調用outer()
時,它還沒有觸及caller
。 只有調用inner
。
問問自己:為什么沒有在這里定義a
和b
的錯誤? 2
const sum = (a, b) => a + b;
sum;
沒錯: sum
甚至沒有被調用! 就像outer()
甚至沒有被調用一樣。
即使更進一步,即使somethingUndefined
沒有在任何地方定義並且不能在任何地方設置,這也不會引發錯誤。 (但你會收到 linter 警告。)
const someFunction = () => somethingUndefined;
someFunction;
盡管在add(5)
分配給addFive
的位置沒有定義b
,但為什么在這個常見的 HOF 示例中沒有出現錯誤?
const add = (a) => {
return (b) => a + b;
};
// Or more simply:
// const add = (a) => (b) => a + b;
const addFive = add(5);
console.log(addFive(3)); // Pints 8.
因為需要b
的 function 即addFive
還沒有被調用。
如果由於未定義caller
而要強制出錯,則必須調用實際需要定義caller
的 function。 有問題的 function 是 external outer()
,您可以像任何其他函數一樣使用()
: outer()()
來調用它。 現在你得到一個TypeError
,因為caller
不是 function。
這種“雙重調用”稱為柯里化。
代碼也可以這樣重寫。 唯一的區別是inner
現在也可以在外部 scope 中訪問,其中outer
是。 請參閱JavaScript 中變量的 scope 是什么? .
const inner = (caller) => {
caller(something);
};
const outer = () => inner;
inner
扮演返回的 function ( outer()
) 的角色。 它將 function 作為參數,並以something
作為參數調用它。
outer
只是返回 function inner
的 function 而已。 它不調用它,它不觸及caller
,它與something
無關。
outer()
和inner
是相同的。
另一方面,如果我省略它並編寫代碼[沒有
caller
],則不會執行這兩個函數firstFuction()
和secondFunction()
。 那么,那個caller
——或者不管它叫什么——究竟是如何工作的呢?
首先,讓我們修復語義: firstFuction()
和secondFunction()
是 function調用。 它們是否是函數,取決於firstFuction
和secondFunction
返回什么。 firstFuction
和secondFunction
是函數(至少代碼暗示它們是函數)。
更具體地說,考慮alert
:
alert
是 function; 您可以將其稱為alert()
。alert()
不是function; 你不能像alert()()
那樣稱呼它。 caller
是一個回調 function。 如果您在代碼中省略caller
,那么myFunction()()
將是正確的調用,不會引發錯誤,只需調用firstFuction
和secondFunction
。
但是回調的重點是將firstFuction
和secondFunction
的結果傳遞給 function caller
。 您必須自己提供 function,例如alert
function。
myFunction()(alert)
調用內部 function,將alert
傳遞給它。 內部 function 調用firstFuction
和secondFunction
並將它們的結果傳遞給我們指定為alert
的caller
。
一旦我將它稱為
myFunction()
,你能告訴我它是如何工作的嗎?
很簡單,這里什么也沒有發生。 myFunction
返回一個 function,就是這樣; function 沒有進一步使用,因此被丟棄。
這段代碼中沒有展示高階函數的一個關鍵方面:封裝值。 考慮這段代碼:
const add = (a) => {
let count = 0;
return (b) => {
++count;
console.log(`The function to add ${a} to something else has been called ${count} time(s).`);
return a + b
};
};
add
和b
的工作方式與之前的myFunction
和caller
類似,但現在,外部 function 也需要一個參數,因此add()
將無濟於事。 add(5)
調用add
function 並將參數a
設置為5
。 此外, add(5)(3)
調用內部,返回 function,將b
設置為3
並返回8
。
但也有一些 state 在add
里面,以一個叫做count
的變量的形式。
const addFive = add(5);
console.log(addFive(3)); // Prints 8.
// But also logs: "The function to add 5 to something else has been called 1 time(s)."
console.log(addFive(10)); // Prints 15.
// But also logs: "The function to add 5 to something else has been called 2 time(s)."
count
只能在outer
訪問(包括其中的任何 function); 它是“封裝的”。 這是隱藏一些 state 的常用方法,這些 state 只能在特定的 function 內訪問。
a
實際上也封裝在add(
... )
中; a
和count
具有相同的 scope 並且彼此沒有什么不同,只是a
可以在調用add
時設置為參數,而count
不能。
然后,您添加了更多上下文,調用看起來更像這樣:
someOtherFunction(myFunction())
這與您剛剛編寫myFunction()
之類的調用之前的情況不同。 現在,結果不會被丟棄,因為它被輸入someOtherFunction
(在原始代碼中: store.dispatch
)。
[
caller
] 沒有作為參數傳遞,也沒有在任何地方定義。
但現在someOtherFunction
的工作是使用適當的回調 function 作為參數調用myFunction()
。 現在,您不要自己通過 function; 相反, someOtherFunction
會為您完成。
將此與JavaScript 回調 function 中的參數從何而來? . 如果您從之前的 go 回到sum
示例 function ,那么您要么自己通過 arguments :
sum(1, 2);
或者一些庫或框架為你做:
// Library code
const doTheRightThing = (callback) => callback(1, 2);
// Your code
doTheRightThing(sum);
或內置(或主機定義) function 為您完成:
[ 1, 2, 3 ].reduce(sum, 0);
這些參數來自哪里或從哪里調用 function 都無關緊要。 但是它被調用了,它在某處被正確的 arguments 調用。
1 :高階function的兩個定義是
outer
符合第一個定義。 outer()
(獨立且巧合地)符合第二個定義。
2 :好的,當然, sum()
也不會拋出錯誤,但是a
和b
仍然是undefined
。 undefined + undefined
具有不會導致錯誤的語義,但希望您明白這一點:在您的原始代碼中, myFunction()()
只會拋出錯誤,因為undefined(firstFunction())
是不可能的。 罪魁禍首是一樣的: caller
是undefined
。
我想你還沒有打印整個片段。 因為,在myFunction()
中沒有對firstFunction()
和secondFunction()
的定義。
要回答您的問題,如果您想調用myFunction()
中定義的 function,您需要將該值分配給一個新變量,因為它返回 function。 然后簡單地撥打 function 電話。
const myFunctionResult = myFunction();
myFunctionResult(someOtherCallerFunction);
但請注意,由於上述原因,這將引發錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.