JavaScriptの関数まとめ

JavaScriptの関数についてまとめました。

関数の種類

関数宣言

関数宣言はfunctionキーワードを使った、最もオーソドックスな関数。

// 関数の定義
function fn() {
    console.log('fn')
}

// 関数の実行
fn()

関数内でreturnを実行するとそれ以降の処理が行われない。returnを記述しない場合はその関数はundefinedを返す。

関数宣言は同じ関数を定義するとエラーではなく上書きされる。

function fn() {
    console.log('fn')
}

function fn() {
    console.log('上書き')
}

fn() // 上書き

意図せず上書きされることは避けたいので、関数はできるだけ関数式を使う。

関数式

関数式は関数を変数に代入したもの。JavaScriptにおける関数はオブジェクトなので値として変数に代入できる。

変数名が関数の呼び出し時の名前になる。

// 関数の定義
const fn = function() {
    // 処理
}

// 関数の実行
fn()

代入する関数には名前をつけることができるが意味はないので、基本的に名前をつけない。関数式に代入する名前がない関数を無名関数という。

関数式は関数が実行されるときに関数オブジェクトが作成されるため、定義する前に実行するとエラーになる。 定義する前に実行してみる。

// varに代入した場合
fn() // Uncaught TypeError: fn is not a function

var fn = function() {
    console.log('fn')
}
// letかconstに代入した場合
fn() // Uncaught ReferenceError: Cannot access 'fn' before initialization

const fn = function() {
    console.log('fn')
}

アロー関数

アロー関数はES6で追加された無名関数を省略して書ける関数。

// 基本的な書き方
const fn = () => {
    console.log('fn')
}

// 仮引数が1つのときは()を省略できる(仮引数がないときは()を省略できない)
const fn = name => {
    console.log(name + ' fn')
}

// 処理が1つの式の場合、{}とreturnを省略できる
const fn = () => console.log('fn')

アロー関数は自身にthisを持たず、外側のアロー関数を囲む関数のthisを参照する。

// グローバルスコープのアロー関数
const fn = () => {
    console.log(this)
}

fn() // Window(グローバルスコープのthis)

// メソッド内のアロー関数
const obj = {
    name: 'オブジェクト',
    method() {

        console.log(this.name) // オブジェクト

        const fn = () => {
            console.log(this.name) // オブジェクト(methodのthis)
        }

        fn()
    }
}

obj.method()

メソッドとして利用するとオブジェクトの参照ではなく、外側の関数やグローバルスコープのthisを参照する。

const obj = {
    name: 'オブジェクト',
    fn: () => {
        console.log(this.name) // undefined
        console.log(this) // Window
    }
}

obj.fn()

また、アロー関数は自身にargumentsを持たない。

const fn = () => {
    console.log(arguments) // Uncaught ReferenceError: arguments is not defined
}

fn()

new演算子を使ってコンストラクタとして使えず、prototypeプロパティを持たない

const Fn = (name) => {
    this.name = name
}

const obj = new Fn('オブジェクト')

console.log(obj.name) // Uncaught TypeError: Fn is not a constructor

これらの特徴からアロー関数はできることが限られているため、コードを書く人によっての差異が生まれにくい。

できるだけ無名関数を書くときはアロー関数を使う。

コールバック関数・高階関数

関数はオブジェクトであるため、関数の引数に渡すこともできる。引数として渡される関数をコールバック関数という。

コールバック関数を引数として使う関数を高階関数という。

function callbackFn() {
    console.log('callback')
}

function fn(callback) {
    callback()
}

fn(callbackFn)

fn高階関数で、関数callbackFnをコールバック関数として引数に受け取り、受け取ったコールバック関数を実行している。

コールバック関数は、非同期処理やイベントリスナー、配列のメソッドなどで使われる。

// 非同期処理
setTimeout(function() {
    // 1秒後に実行されるコールバック関数の処理
}, 1000);


// イベントリスナー
const btn = document.getElementById('button')

btn.addEventListener('click', function() {
    // ボタンがクリックされた時のコールバック関数の処理
})


// 配列のメソッド
const numbers = [1, 2, 3, 4, 5]

// mapメソッドは配列の要素1つずつに対して引数に与えられたコールバック関数を実行し、その結果を新しい配列として返すメソッド
const doubled = numbers.map(num => num * 2)

即時関数

即時関数は関数の定義と実行を同時に行う関数。関数スコープを作って、スコープの汚染を防ぐために使われる。

(function () {
    // この中で定義した変数はローカル変数になる
    var a = 'local'
    
    console.log(a) // local
})()

console.log(a) // Uncaught ReferenceError: a is not defined

function () {}を包んでいる()は算術の優先度を決めるためのもので、その後の()は関数の実行のためのもの。

普通の関数同様、引数を指定することもできる。

(function (a) {
    console.log(a) // local
})('local')

オブジェクトのメソッド

オブジェクトに定義した関数をメソッドという。

const obj = {
    fn() {
        console.log('fn')
    },

    // 関数宣言
    fn2: function() {
        console.log('fn2')
    },

    // アロー関数
    fn3: () => {
        console.log('fn3')
    }
}

obj.fn() // fn
obj.fn2() // fn2
obj.fn3() // fn3

引数

JavaScriptの関数は仮引数と実際に渡した引数の数が違っても実行できる。

渡した引数が足りない場合は仮引数にはundefinedが渡される。

function fn(a, b) {
    console.log(a) // fn
    console.log(b) // undefined
}

fn('fn')

渡した引数が多い時は、不必要な引数は無視される。

function fn(a) {
    console.log(a);
}

fn(0, 1) // 1は無視される

デフォルト引数

デフォルト引数は仮引数に値を指定しておくことで、実引数に値を指定しない場合でも勝手に値が指定されるようにするための引数。

function fn(a = 0) {
    console.log(a) // 0
}

fn()

arguments

argumentsは関数の中でのみ使える引数の全ての値が格納された変数。

配列のようにインデックスでアクセスできるが、配列のメソッドは使えない。

function fn() {
    console.log(arguments) // Arguments(4) ['a', 'r', 'g', 'u', callee: ƒ, Symbol(Symbol.iterator): ƒ]
    console.log(arguments[0]) // a
    console.log(arguments[1]) // r
    console.log(arguments[2]) // g
    console.log(arguments[3]) // u
}

fn('a', 'r', 'g', 'u')

上記のように仮引数を指定したり、引数の数を固定しなくても、引数に与えられた値を参照できる。

しかしargumentsだと引数を受け取るのか、引数をどれだけ受け取るのかが明確ではなく、またアロー関数では使えないので、できれば可変長引数を受け取ることを明確にするRest parametersを使う。

Rest parameters

Rest parametersはES6で追加された仮引数に...をつけたもので、argumentsとは違い、可変長引数を受け取ることを明確にし、受け取った引数を配列として扱える。

function fn(...args) {
    console.log(args) // (9) ['a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's']
}

fn('a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's')

まとめ

  • 関数はできるだけ関数宣言ではなくアロー関数を使った関数式を使う
  • 関数にreturnを指定しないとundefinedを返す
  • コールバック関数は関数の引数として渡される関数
  • 即時関数はスコープの汚染を防ぐために使う
  • 可変長引数を受け取るときはできるだけargumentsではなくRest parametersを使う