簡體   English   中英

盡管參數未定義,但返回 function 的 Function 不會引發錯誤

[英]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

在上面的代碼中, twicetriple基本上如下

 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

問問自己:為什么沒有在這里定義ab的錯誤? 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調用 它們是否函數,取決於firstFuctionsecondFunction返回什么。 firstFuctionsecondFunction函數(至少代碼暗示它們是函數)。

更具體地說,考慮alert

  • alert是 function; 您可以將其稱為alert()
  • alert()不是function; 你不能像alert()()那樣稱呼它。

caller是一個回調 function。 如果您在代碼中省略caller ,那么myFunction()()將是正確的調用,不會引發錯誤,只需調用firstFuctionsecondFunction

但是回調的重點是將firstFuctionsecondFunction的結果傳遞給 function caller 您必須自己提供 function,例如alert function。

myFunction()(alert)調用內部 function,將alert傳遞給它。 內部 function 調用firstFuctionsecondFunction並將它們的結果傳遞給我們指定為alertcaller


一旦我將它稱為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
  };
};

addb的工作方式與之前的myFunctioncaller類似,但現在,外部 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( ... )中; acount具有相同的 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的兩個定義是

  1. 一個 function 返回一個 function,或
  2. 一個 function 將另一個 function 作為參數。

outer符合第一個定義。 outer() (獨立且巧合地)符合第二個定義。

2 :好的,當然, sum()也不會拋出錯誤,但是ab仍然是undefined undefined + undefined具有不會導致錯誤的語義,但希望您明白這一點:在您的原始代碼中, myFunction()()只會拋出錯誤,因為undefined(firstFunction())是不可能的。 罪魁禍首是一樣的: callerundefined

我想你還沒有打印整個片段。 因為,在myFunction()中沒有對firstFunction()secondFunction()的定義。

要回答您的問題,如果您想調用myFunction()中定義的 function,您需要將該值分配給一個新變量,因為它返回 function。 然后簡單地撥打 function 電話。

const myFunctionResult = myFunction();
myFunctionResult(someOtherCallerFunction);

但請注意,由於上述原因,這將引發錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM