LoginSignup
1
0

JavaScriptのforEachループ内でreturnを使用して詰まった

Posted at

はじめに

学習用のメモとして投稿します。
JavaScriptで練習問題を解く機会があり、その際にforEachメソッドの挙動で少し戸惑いました。
その原因と解決策について書いていきます。

問題の挙動

実際のものから少し変更していますが、練習問題の内容は次のようなものです。

  • ユーザー名 username を引数に受け取り、権限が許可されているかどうかを判定する関数 checkPermission を実装してください。
  • ユーザーの権限は、次のようなオブジェクトの配列 users に格納されています。
let users = [
  {
    username: '斉藤',
    hasPermission: true
  },
  {
    username: '齋藤',
    hasPermission: false
  },
];

▼呼び出し例

console.log(checkPermission('斉藤')) // true
console.log(checkPermission('齋藤')) // false

引数で与えられたユーザーが存在しない場合の処理など細かい点は置いておくとして、とりあえずforEachを使用すれば実装できるのではないかと思い、次のような実装を考えました。

function checkPermission(username) {
  users.forEach(user => {
    if (user.username == username) {
      return user.hasPermission
    }
  })
}

console.log(checkPermission('斉藤'))// undefined
console.log(checkPermission('齋藤')) // undefined

想定では、true又はfalseが表示されるはずでしたが、実際に動かしてみると結果はどちらもundefinedでした。。

原因

真偽値をreturnしているのに、何故undefinedなのか、最初は理解できませんでしたが、公式ドキュメントに記載がありました。

forEach() は配列の各要素に対して callbackFn 関数を一度ずつ実行します。map() や reduce() と異なり、返値は常に undefined であり、チェーンできません。チェーンの最後に副作用を生じさせるのが典型的な使用法です。

メモ: 例外を発生する以外の方法で、forEach() ループを止めることはできません。ループ中に中断する必要がある場合、forEach() メソッドは適切な方法ではありません。

ループ中に中断できないということで、forEach内でbreakやcontinueを使用するのも適切ではないようです。

forEachは、配列の要素を取り出して、一つずつコールバックに渡しています。forEach内でreturnが使用されると、次の要素をコールバックに渡す処理に移ります。これはループ内でcontinueを使用したのと同様の挙動で、最後の要素をコールバックに渡した後、最終的にはundefindが返ってくることになります。

これを踏まえて、コードを次のように修正しました。

function checkPermission(username) {
  const user = users.find(user => user.username === username)
  if (user) {
    return user.hasPermission;
  } else {
    return undefined;
  }
}

console.log(checkPermission2('斉藤'))// true
console.log(checkPermission2('齋藤')) // false

これで想定通り動くようになりました。
他の言語ではあまりこのような挙動は見ないように思いますが(と言いつつそこまで詳しいわけではない)、、ちょっとクセがあるなと感じました。

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0