亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

可讀性與可維護性:嵌套函數

可讀性與可維護性:嵌套函數

呼啦一陣風 2023-09-14 20:18:02
考慮到長期影響(增加函數/參數的數量、其他開發人員接管等),每個選項的優缺點是什么?選項 1:無需將foo和傳遞bar給每個方法,但會創建難以理解的嵌套函數。const myFunction = ({foo, bar}) => {  const results = []  const function1 = () => {    return foo + bar;  }  const function2 = () => {    return foo * bar;  }  const res1 = function1();  const res2 = function2();  results.push(res1, res2);  return results;}選項 2:將參數傳遞給每個函數,但刪除嵌套,我認為這使其更具可讀性。const function1 = ({foo, bar}) => {  return foo + bar;}const function2 = ({foo, bar}) => {  return foo * bar;}const myFunction = ({foo, bar}) => {  const results = []  const res1 = function1({foo, bar});  const res2 = function2({foo, bar});  results.push(res1, res2);  return results;}我更想知道如何改進我的功能方法。謝謝你!
查看完整描述

3 回答

?
收到一只叮咚

TA貢獻1821條經驗 獲得超5個贊

第二種方法更為慣用。事實上,第二種方法在函數式編程中有一個名字。將共享靜態值作為輸入(又稱為環境)的函數稱為reader。

// Reader e a = e -> a


// ask : Reader e e

const ask = x => x;


// pure : a -> Reader e a

const pure = x => _ => x;


// bind : Reader e a -> (a -> Reader e b) -> Reader e b

const bind = f => g => x => g(f(x))(x);


// reader : Generator (Reader e a) -> Reader e a

const reader = gen => (function next(data) {

? ? const { value, done } = gen.next(data);

? ? return done ? value : bind(value)(next);

}(undefined));


// Environment = { foo : Number, bar : Number }


// function1 : Reader Environment Number

const function1 = reader(function* () {

? ? const { foo, bar } = yield ask;

? ? return pure(foo + bar);

}());


// function2 : Reader Environment Number

const function2 = reader(function* () {

? ? const { foo, bar } = yield ask;

? ? return pure(foo * bar);

}());


// myFunction : Reader Environment (Array Number)

const myFunction = reader(function* () {

? ? const res1 = yield function1;

? ? const res2 = yield function2;

? ? return pure([res1, res2]);

}());


// results : Array Number

const results = myFunction({ foo: 10, bar: 20 });


console.log(results);

在上面的示例中,我們使用一元表示法定義function1function2、 和。myFunction請注意,myFunction沒有明確將環境作為輸入。它也沒有顯式地將環境傳遞給function1function2。所有這些“管道”都是由purebind函數處理的。我們使用一元動作訪問一元上下文中的環境ask。

Reader然而,當我們使用 monad 轉換器將 monad 與其他 monad結合起來時,真正的優勢就會出現ReaderT。


編輯:如果您不想,則不必使用單子表示法。您可以按如下方式定義function1function2、 和。myFunction

// Reader e a = e -> a


// Environment = { foo : Number, bar : Number }


// function1 : Reader Environment Number

const function1 = ({ foo, bar }) => foo + bar;


// function2 : Reader Environment Number

const function2 = ({ foo, bar }) => foo * bar;


// myFunction : Reader Environment (Array Number)

const myFunction = env => {

? ? const res1 = function1(env);

? ? const res2 = function2(env);

? ? return [res1, res2];

};


// results : Array Number

const results = myFunction({ foo: 10, bar: 20 });


console.log(results);

缺點是現在您明確地將環境作為輸入并將環境傳遞給子計算。不過,這可能是可以接受的。


編輯:這是另一種編寫方法,不使用一元符號,但仍然使用ask、pure和bind。


// Reader e a = e -> a


// ask : Reader e e

const ask = x => x;


// pure : a -> Reader e a

const pure = x => _ => x;


// bind : Reader e a -> (a -> Reader e b) -> Reader e b

const bind = f => g => x => g(f(x))(x);


// Environment = { foo : Number, bar : Number }


// function1 : Reader Environment Number

const function1 = bind(ask)(({ foo, bar }) => pure(foo + bar));


// function2 : Reader Environment Number

const function2 = bind(ask)(({ foo, bar }) => pure(foo * bar));


// myFunction : Reader Environment (Array Number)

const myFunction =

? ? bind(function1)(res1 =>

? ? ? ? bind(function2)(res2 =>

? ? ? ? ? ? pure([res1, res2])));


// results : Array Number

const results = myFunction({ foo: 10, bar: 20 });


console.log(results);

請注意,使用生成器的一元表示法只是上述代碼的語法糖。




查看完整回答
反對 回復 2023-09-14
?
躍然一笑

TA貢獻1826條經驗 獲得超6個贊

您的兩種方法都是正確的。這里的問題是該代碼與應用程序相關的上下文,這些函數是否與它們定義/使用的范圍相關?


考慮這個例子。


const Calculator = class {

    complexOperation({foo, bar}) {

      const results = []


      const res1 = this.sum({foo, bar});

      const res2 = this.dot({foo, bar});


      results.push(res1, res2);


      return results;

    }


    sum({foo, bar}) {

      return foo + bar;

    }


    dot({foo, bar}){

      return foo * bar;

    }

};


var calc = new Calculator();

calc.complexOperation({foo: 2, bar: 3})

在這個例子中,我們可以看到功能級抽象是如何與意圖相關的。


永遠記住牢記“降職規則”。


現在讓我們改變應用意圖?,F在我們正在向法律機構申請,我們必須進行復雜的操作來申請一些稅收。


現在 sum 和點不應該成為類的一部分,因為只會在復雜操作中使用,新開發人員不關心 function1(我將其重命名為 sum)做什么,他們不必閱讀它,所以我們可以改變抽象級別。事實上,您將以包含一些步驟的方法結束。


在其他語言中,例如c#,您可以在使用后定義函數,但在javascript中則不能,因此您不能在JS中的本地函數中應用Stepdown規則。有些人顛倒了Stepdown Rule,將所有局部函數都定義在函數start中,所以他們的眼睛就跳到最后一個局部函數結束括號并開始閱讀。


const BusinessTaxes = class {

    complexOperation({foo, bar}) {

      const addTax = () => {

        return foo + bar;

      }

        

      const dotTax = () => {

        return foo * bar;

      }


      // Jump your eyes here

      const results = []

            

      const res1 = addTax({foo, bar});

      const res2 = dotTax({foo, bar});


      results.push(res1, res2);


      return results;

    };

};


var businessTax= new BusinessTaxes();

businessTaxes.complexOperation({foo: 2, bar: 3})

總之,將您的代碼組織成相同的抽象級別,保持其結構化并與您的決策保持一致,您的代碼將具有可讀性和可維護性。


查看完整回答
反對 回復 2023-09-14
?
慕的地6264312

TA貢獻1817條經驗 獲得超6個贊

當開發人員專注于明確自己的意圖時,可讀性往往是一個副產品。

下一個開發人員(或未來的您)會理解您的意圖嗎?

恕我直言,這是您應該回答的唯一問題嗎,因為它關注的是比“這看起來不錯嗎?”更具體的問題。

從這個角度來看,兩個版本都做到了這一點。

除了兩者:

  • 可以用更好的名字

  • 可以使用新的語法來使其更容易被眼睛看到

const sumproduct_pair = ({a, b}) => {

  const sum = () => a + b;

  const product = () => a * b;

  return [sum(), product()];

};

或者


const sum = ({a, b}) => a + b;

const product = ({a, b}) => a * b;

const sumproduct_pair = ({a, b}) => [sum({a, b}), product({a, b})];

然而,這兩個版本都可以改進,但還是 YMMV:


在第一個版本中, 和sum都不product需要存在。它們顯然不適合重復使用,而且非常簡單,可以簡化為最簡單的表達:


const sumproduct_pair = ({a, b}) => [a+b, a*b];

在第二個版本中,如果您打算重用sum并重product用,請考慮“針對接口而不是實現進行設計”。


該函數sumproduct_pair需要一個具有屬性的對象a,b但這并不意味著所有其他函數都需要具有相同的接口:


const sum = (a, b) => a + b;

const product = (a, b) => a * b;

const sumproduct_pair = ({a, b}) => [sum(a, b), product(a, b)];

雖然這看起來像是一個微不足道的更改,但它刪除了一些不必要的大括號(如果您想通過減少編寫來提高可讀性),最重要的是允許 和 處理sum未知product數量的數字:


const sum = (...xs) => xs.reduce((ret, x) => ret + x, 0);

const product = (...xs) => xs.reduce((ret, x) => ret * x, 1);


sum(1, 2, 3);        //=> 6

sum(1, 2, 3, 4);     //=> 10

product(1, 2, 3);    //=> 6

product(1, 2, 3, 4); //=> 24


查看完整回答
反對 回復 2023-09-14
  • 3 回答
  • 0 關注
  • 157 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號