LoginSignup
13
10

More than 5 years have passed since last update.

JavaScript の関数に関するあれこれ

Posted at

JavaScript シリーズの最後は、JavaScript の関数に関するまとめ。自分の知らないことを中心にいくつかサンプルを書いて見ます。

関数の順番

JavaScript では、関数の定義は、関数を使用する前でも、後でも構いません。実行される時に、関数は全て前に持ってこられます。

arguments

JavaScript には予約されているarguments というプロパティがあります。それを使うと、可変のプロパティも扱えます。

function printArgs() {
    for (i = 0; i < arguments.length; i++) {
        console.log(arguments[i])
    }
}
x = printArgs(1, true, "Hello")

実行結果

1
true
Hello

関数の引数

関数の引数には、値渡しと、参照渡しがあります。プリミティブ型は値渡しで、オブジェクトだと参照渡しとのことです。下記の例では、statement は、文字列型、empはオブジェクトです。
changeValues 内で、パラメータに対して新しい値をアサインしていますが、実際に反映されるのは、オブジェクト (emp) のみです。

function changeValues(statement, emp) {
    statement = "Hi, guys";
    emp.name = "Taro";
}

var statement = "Hello guys";
var emp = new Employee("Yamada");

console.log(statement);
console.log(emp.name);
changeValues(statement, emp);
console.log(statement);
console.log(emp.name);

実行結果

Hello guys
Yamada
Hello guys
Taro

call

メソッドを呼び出す方法はいくつかありますが、その一つが、call を使う方法です。call を使うと、他のオブジェクトに属するメソッドを使えます。下記の例では、emp のメソッドを、myEmp の属性に対して実行しています。

var emp = {
    name: "Tsuyoshi",
    baseSalary: 100,
    salary: function() {
        return this.baseSalary * 2 + 1;
    }
}

var myEmp = {
    name: "Takeru",
    baseSalary: 200
}

console.log(emp.name);
console.log(emp.salary());
console.log(emp.salary.call(myEmp));
Tsuyoshi
201
401

apply

call とほぼ同じですが、引数を配列で扱えます。

console.log(Math.max.apply(null, [4,6,90]))
console.log(Math.max.call(null, 39,20,1))
90
39

self invoke method

関数は通常定義するだけでは、実行されませんが、定義して、即実行したい時に使います。

var value = "default";

// self invoke method

(function () {
    value = "hello!";
})();

console.log(value);

(function() {...})(); とすることにより、その場で関数が実行されるので、value の値が書き換えられます。実行結果はこちら。

hello!

closure

クロージャを使うと、関数に、通常 JavaScript ではできない、プライベートのプロパティや、関数を持つことができます。ポイントは、戻り値として関数を返しているところです。素直に考えると、関数を返した時点では、演算は行われず、関数を実行した時点での、counter が参照されそうです。ところが、クロージャでは、この関数が戻された時の、状態を保持したまま返されます。

だから、次のようなコードを書くと、add1 add2 それぞれで、値がインクリメントされます。

var add1 = (function () {
    var counter = 0;
    return function() {return counter += 1;}
})();

var add2 = (function () {
    var counter = 0;
    return function() {return counter += 1;}
})();

console.log(add1());
console.log(add1());
console.log(add2());
console.log(add2());

実行結果

1
2
1
2

通常の関数と、クロージャの違い

通常の関数と比べると、クロージャは関数を返しています。通常の関数だと、毎回countが初期化されるため、値を保持できません。

unction execFunc() {
    var count = 0;
    function add() {
        count++;
    }
    function display() {
        console.log(count);
    }
    add();
    display();
}

execFunc();
execFunc();

function execClosure() {
    var count = 0;
    return {
        add: function() {
            count++;
        },
        display: function() {
            console.log(count);
        }
    }
};

var closure = execClosure();
closure.add();
closure.display();
closure.add();
closure.display();

実行結果

1
1
1
2

Private の実現

この仕組みを利用して、プライベート属性を実現することができます。クロージャが戻されると、元々の関数の方には、クロージャからアクセスできますが、直接はアクセスできません。


var count = (function() {
    var counter = 0;
    function modify(num) {
        counter += num;
    }

    return {
        add: function() {
            modify(1);
        },
        remove: function() {
            modify(-1);
        },
        get: function() {
            return counter;
        }
    };
})();

console.log(count.get());
count.add();
count.add();
console.log(count.get());
count.remove();
console.log(count.get());

count.modify(1); // error

実行結果

0
2
1

 count.modify(1); // error
       ^

TypeError: count.modify is not a function

クロージャとクラス

ちなみに、状態を持てるということは、クラスと何が違うの?と思ってしまいます。

クロージャとクラスを比較すると、クロージャーの方がメモリをよく食う(メソッドが毎回インスタンス化されるので)しかし、テスタビリティは優れているという話もあります。(まだ調べていません。メモ程度)。となると、後のメリットである、Private を作れるという話ですが、ここまでやって、private を作るべきか?というと微妙かもと思います。効率を考えると基本クラスで問題なさげですが、クロージャの良いユースケースがあったらぜひ教えてください。

次のリソースの中には、DI を使っているときはクロージャはしやすいという記事がありました。ちなみに、使っていないときは、Class の方がモックが楽で、Clousure を使っているとできるけどダークマジックが必要とあります。clousure は liablity (責任を持つこと)に有利で、class はメモリ効率で有利とあります。

リソース

13
10
0

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
13
10