ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript で複雑な判断を記述するエレガントな方法

JavaScript で複雑な判断を記述するエレガントな方法

hzc
hzc転載
2020-06-16 09:51:151997ブラウズ

前提


JSコードを書く際、複雑な論理判断に遭遇することがよくありますが、通常はif/elseやswitchを使って複数の条件判断を実装できますが、これには問題があります。ロジックが複雑になるにつれて、コード内の if/else/switch はますます肥大化し、理解しにくくなります。そこで、判定ロジックをよりエレガントに記述するにはどうすればよいでしょうか?この記事で一度試してみましょう。

最初にコードを見てください

/**
 * 按钮点击事件
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 商品售罄 4 开团成功 5 系统取消
 */
const onButtonClick = (status)=>{
  if(status == 1){
    sendLog('processing')
    jumpTo('IndexPage')
  }else if(status == 2){
    sendLog('fail')
    jumpTo('FailPage')
  }else if(status == 3){
    sendLog('fail')
    jumpTo('FailPage')
  }else if(status == 4){
    sendLog('success')
    jumpTo('SuccessPage')
  }else if(status == 5){
    sendLog('cancel')
    jumpTo('CancelPage')
  }else {
    sendLog('other')
    jumpTo('Index')
  }
}

コードを通して、このボタンのクリック ロジックを確認できます。さまざまなアクティビティの状態に応じて 2 つのことを実行します。ログを送信してポイントを埋め、対応するページにジャンプします。このコードの書き換え計画を簡単に提案できます。スイッチが表示されます:

/**
 * 按钮点击事件
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 商品售罄 4 开团成功 5 系统取消
 */
const onButtonClick = (status)=>{
  switch (status){
    case 1:
      sendLog('processing')
      jumpTo('IndexPage')
      break
    case 2:
    case 3:
      sendLog('fail')
      jumpTo('FailPage')
      break  
    case 4:
      sendLog('success')
      jumpTo('SuccessPage')
      break
    case 5:
      sendLog('cancel')
      jumpTo('CancelPage')
      break
    default:
      sendLog('other')
      jumpTo('Index')
      break
  }
}

まあ、これは if/else よりもはるかに明確に見えます。慎重な学生は、ちょっとしたヒント、ケース 2 とケース 3 のロジックが同じ場合、実行文を省略してブレークすると、ケース 2 でケース 3 のロジックが自動的に実行されます。

このとき、学生の中には、もっと簡単に書く方法があると言う人もいます:

const actions = {
  '1': ['processing','IndexPage'],
  '2': ['fail','FailPage'],
  '3': ['fail','FailPage'],
  '4': ['success','SuccessPage'],
  '5': ['cancel','CancelPage'],
  'default': ['other','Index'],
}
/**
 * 按钮点击事件
 * @param {number} status 活动状态:1开团进行中 2开团失败 3 商品售罄 4 开团成功 5 系统取消
 */
const onButtonClick = (status)=>{
  let action = actions[status] || actions['default'],
      logName = action[0],
      pageName = action[1]
  sendLog(logName)
  jumpTo(pageName)
}

上記のコードは見た目がすっきりしていますが、この方法の賢い点は、判定条件を使用していることです。オブジェクトとして 属性名は処理ロジックをオブジェクトの属性値として使用し、ボタンをクリックするとオブジェクトの属性を検索して論理的に判定するため、特に単項の条件判定に適した記述方法です。

他の書き方はありますか?一部:

const actions = new Map([
  [1, ['processing','IndexPage']],
  [2, ['fail','FailPage']],
  [3, ['fail','FailPage']],
  [4, ['success','SuccessPage']],
  [5, ['cancel','CancelPage']],
  ['default', ['other','Index']]
])
/**
 * 按钮点击事件
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 商品售罄 4 开团成功 5 系统取消
 */
const onButtonClick = (status)=>{
  let action = actions.get(status) || actions.get('default')
  sendLog(action[0])
  jumpTo(action[1])
}

このように書くと、es6 では Map オブジェクトが使用されます。 Map オブジェクトと Object オブジェクトの違いは何ですか?

  1. オブジェクトには通常、独自のプロトタイプがあるため、オブジェクトには常に「プロトタイプ」キーがあります。

  2. オブジェクトのキーは文字列またはシンボルのみですが、マップのキーは任意の値にすることができます。

  3. マップのキーと値のペアの数は、size 属性を通じて簡単に取得できますが、オブジェクトのキーと値のペアの数は手動でのみ確認できます。

問題をアップグレードする必要があります。以前は、ボタンをクリックしたときのステータスを判断するだけで済みましたが、今ではユーザーの ID も判断する必要があります:

/**
 * 按钮点击事件
 * @param {number} status 活动状态:1开团进行中 2开团失败 3 开团成功 4 商品售罄 5 有库存未开团
 * @param {string} identity 身份标识:guest客态 master主态
 */
const onButtonClick = (status,identity)=>{
  if(identity == 'guest'){
    if(status == 1){
      //do sth
    }else if(status == 2){
      //do sth
    }else if(status == 3){
      //do sth
    }else if(status == 4){
      //do sth
    }else if(status == 5){
      //do sth
    }else {
      //do sth
    }
  }else if(identity == 'master') {
    if(status == 1){
      //do sth
    }else if(status == 2){
      //do sth
    }else if(status == 3){
      //do sth
    }else if(status == 4){
      //do sth
    }else if(status == 5){
      //do sth
    }else {
      //do sth
    }
  }
}

すべての判断を書いていないことをごめんなさい。ここでの具体的なロジックは、コードが長すぎるためです。

また if/else を使用することをご容赦ください。論理的判断のこのような大規模なセクションを記述するために、今でも if/else を使用している人がたくさんいるためです。

上記の例を見ると、ロジックを二項判定にバージョンアップすると判定量が2倍になり、コード量も2倍になることがわかりますが、このときどうすればよりスッキリと書けるでしょうか?

const actions = new Map([
  ['guest_1', ()=>{/*do sth*/}],
  ['guest_2', ()=>{/*do sth*/}],
  ['guest_3', ()=>{/*do sth*/}],
  ['guest_4', ()=>{/*do sth*/}],
  ['guest_5', ()=>{/*do sth*/}],
  ['master_1', ()=>{/*do sth*/}],
  ['master_2', ()=>{/*do sth*/}],
  ['master_3', ()=>{/*do sth*/}],
  ['master_4', ()=>{/*do sth*/}],
  ['master_5', ()=>{/*do sth*/}],
  ['default', ()=>{/*do sth*/}],
])

/**
 * 按钮点击事件
 * @param {string} identity 身份标识:guest客态 master主态
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 开团成功 4 商品售罄 5 有库存未开团
 */
const onButtonClick = (identity,status)=>{
  let action = actions.get(`${identity}_${status}`) || actions.get('default')
  action.call(this)
}

上記のコードの核となるロジックは、2 つの条件を 1 つの文字列に結合し、条件文字列をキーとして、処理関数を値として使用して Map オブジェクトを検索および実行するというものです。この記述方法は次のとおりです。複数で使用されます。特に条件判断をする場合に便利です。

もちろん、上記のコードは、Object オブジェクトを使用して実装されている場合も同様です。

const actions = {
  'guest_1':()=>{/*do sth*/},
  'guest_2':()=>{/*do sth*/},
  //....
}

const onButtonClick = (identity,status)=>{
  let action = actions[`${identity}_${status}`] || actions['default']
  action.call(this)
}

クエリ条件を文字列に記述するのが少し面倒だと感じる学生がいる場合は、次のコードがあります。別の解決策は、Map オブジェクトを使用し、Object オブジェクトをキーとして使用することです:

const actions = new Map([
  [{identity:'guest',status:1},()=>{/*do sth*/}],
  [{identity:'guest',status:2},()=>{/*do sth*/}],
  //...
])

const onButtonClick = (identity,status)=>{
  let action = [...actions].filter(([key,value])=>(key.identity == identity && key.status == status))
  action.forEach(([key,value])=>value.call(this))
}

これはもう少し高度ですか?

Map と Object の違いは、ここでも参照できます。Map は、任意のタイプのデータをキーとして使用できます。

ここで、難易度を少しアップグレードします。ゲストの場合、ステータス 1 ~ 4 の処理ロジックが同じである場合はどうなるでしょうか。最悪のケースは次のとおりです。

const actions = new Map([
  [{identity:'guest',status:1},()=>{/* functionA */}],
  [{identity:'guest',status:2},()=>{/* functionA */}],
  [{identity:'guest',status:3},()=>{/* functionA */}],
  [{identity:'guest',status:4},()=>{/* functionA */}],
  [{identity:'guest',status:5},()=>{/* functionB */}],
  //...
])

A better way to write it is 処理ロジックをキャッシュする function

const actions = ()=>{
  const functionA = ()=>{/*do sth*/}
  const functionB = ()=>{/*do sth*/}
  return new Map([
    [{identity:'guest',status:1},functionA],
    [{identity:'guest',status:2},functionA],
    [{identity:'guest',status:3},functionA],
    [{identity:'guest',status:4},functionA],
    [{identity:'guest',status:5},functionB],
    //...
  ])
}

const onButtonClick = (identity,status)=>{
  let action = [...actions()].filter(([key,value])=>(key.identity == identity && key.status == status))
  action.forEach(([key,value])=>value.call(this))
}

このように書けば日常的なニーズは満たせますが、正直なところ、上記の functionA を 4 回も書き直すのはまだ少し抵抗があります。特に判定条件が複雑になる場合は、たとえば、アイデンティティは 3 ステータスには 10 の状態があります。その場合、30 の処理ロジックを定義する必要がありますが、これらのロジックの多くは同じであることがよくあります。これは受け入れたくないことのようです。次のように実装できます。 this:

const actions = ()=>{
  const functionA = ()=>{/*do sth*/}
  const functionB = ()=>{/*do sth*/}
  return new Map([
    [/^guest_[1-4]$/,functionA],
    [/^guest_5$/,functionB],
    //...
  ])
}

const onButtonClick = (identity,status)=>{
  let action = [...actions()].filter(([key,value])=>(key.test(`${identity}_${status}`)))
  action.forEach(([key,value])=>value.call(this))
}

Here Map の利点はさらに顕著です。通常の型をキーとして使用できるため、無限の可能性が広がります。すべてのゲストの状況に対してログの埋め込みポイントを送信する必要がある場合、

const actions = ()=>{
  const functionA = ()=>{/*do sth*/}
  const functionB = ()=>{/*do sth*/}
  const functionC = ()=>{/*send log*/}
  return new Map([
    [/^guest_[1-4]$/,functionA],
    [/^guest_5$/,functionB],
    [/^guest_.*$/,functionC],
    //...
  ])
}

const onButtonClick = (identity,status)=>{
  let action = [...actions()].filter(([key,value])=>(key.test(`${identity}_${status}`)))
  action.forEach(([key,value])=>value.call(this))
}

つまり、配列ループの特性を利用して、規則的な条件を満たすロジックが実行されます。その後、パブリック ロジックと個別のロジックを同時に実行することも可能です 規則的なルールが存在するため、想像力を広げて解き放つことができます 遊び方は他にもありますが、この記事では詳しく説明しません。

概要

この記事では、次のような論理的な判断を書く 8 つの方法を説明しました。

  1. if/else

  2. switch

  3. 一元判定の場合:オブジェクトに保存

  4. 一方通行の判定の場合:オブジェクトに保存Map

  5. 複数の判定を行う場合: 条件を文字列に結合して Object に保存します

  6. 複数の判定を行う場合: 条件を結合してオブジェクトに保存します文字列にしてMapに保存

  7. 複数判定する場合:条件をObjectとして保存してMapに保存

  8. #判定する場合複数の判断: マップに条件を正規表現として保存

この記事はこれで終わりとなりますが、今後の人生が if/else だけではないことを願っています。 /スイッチ。

推奨チュートリアル: 「JS チュートリアル

以上がJavaScript で複雑な判断を記述するエレガントな方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。