TypeScriptに入門したいのでJavaScriptに入門してみる(関数と宣言)
続: JavaScript入門
教材は
関数と宣言
関数は function
キーワードを使う。
function function_name(arg1, arg2) {
// something to do...
return return_value;
}
// 関数の呼び出し
const result = function_name(arg1, arg2);
関数名のルールは変数名のルールと同じ
- 半角のアルファベット、
_
(アンダースコア)、$
(ダラー)、数字を組み合わせた名前にする - 変数名は数字から開始できない
- 予約語と被る名前は利用できない
- returnは必須ではない(値を返す必要がない関数はreturnを書く必要はない)
- returnの返り値を省略している場合、もしくはreturn 文のそのものを省略した場合は未定義の値である undefined を返す。
関数の引数
定義した関数の仮引数よりも呼び出し時の引数が少ない場合、余った仮引数には undefined という値が代入される。(エラーにならないんですね…)
function echo(x) {
return x;
}
console.log(echo(1)); // -> 1
console.log(echo()); // -> undefined
また、引数の数が多い時は余分な引数は単純に無視される。
[ES2015] デフォルト引数
Pythonなどと同じくデフォルト引数が使える。
function echo(x = "hoge") {
return x;
}
console.log(echo(1)); // -> 1
console.log(echo()); // -> hoge
デフォルト引数が導入されるまではOR演算子を使ったデフォルト値の指定がよく利用されていたらしいがバグを生みやすいので使わない方が良さそう。
可変長引数
可変長引数を使うには Rest parameters を使うか、arguments
という特殊な変数を利用する。
[ES2015] Rest parameters
function fn(...args) {
console.log(args); // -> ["a", "b", "c"];
}
fn("a", "b", "c");
...args
と書かれている部分がRest parametersと呼ばれる可変長引数の部分。argsはRest parametersの名前なので、すきな変数名が使えるっぽい。
function fn(arg1, ...restArgs) {
console.log(arg1); // -> "a"
console.log(restArgs); // -> ["b", "c"];
}
fn("a", "b", "c");
通常の仮引数と組み合わせて定義することもできるが、Rest parametersは 必ず末尾の引数にしなければならない。
function fn(x, y, z) {
console.log(x);
console.log(y);
console.log(z);
}
const array = [1, 2, 3];
// Spread構文で配列を引数に展開して関数を呼び出す
fn(...array);
// 次のように書いたのと同じ意味
fn(array[0], array[1], array[2]);
Spread構文は、 配列の前に ...
をつけた構文 のことで、関数には配列の値を展開したものが引数として渡される。
arguments
Rest parameters を使えない場合のみ利用すべき機能が arguments
。
可変長引数を扱う別の方法として、 arguments
という関数の中のみで参照可能な特殊な変数がある。
arguments
は関数に渡された引数の値がすべて入った Array-like なオブジェクトで、配列のようにインデックスで要素へアクセスができるが、 Array
ではないので、実際の配列とは異なり Array
のメソッドは利用できないという特殊なオブジェクトである。
function fn() {
// `arguments` はインデックスを指定して各要素にアクセスできる
console.log(arguments[0]); // -> "a"
console.log(arguments[1]); // -> "b"
console.log(arguments[2]); // -> "c"
}
fn("a", "b", "c");
[ES2015] 関数の引数と分割代入
function printUserId({ id }) {
console.log(id);
}
const user = {
id: 42
};
printUserId(user);
関数の引数に分割代入を使うことができる。 分割代入を使わなかった場合は以下のような書き方になる。
function printUserId(user) {
console.log(user.id);
}
const user = {
id: 42
};
printUserId(user);
function print([first, second]) {
console.log(first); // -> 1
console.log(second); // -> 2
}
const array = [1, 2];
print(array);
関数はオブジェクト
関数はオブジェクトとして参照できる(関数オブジェクトという)
()
をつけなければ関数オブジェクトとして参照できる。
function fn() {
console.log("hoge");
}
const myFunc = fn;
myFunc();
関数が値として扱えることを ファーストクラスファンクション(第一級関数) と呼ぶ。
関数式
関数式とは関数を値として変数へ代入している式のことを言う。
無名関数ですね。
const func_name = function() {
// something to do
return return_value;
};
再帰の例でよくある累乗を求める場合の、関数式に名前をつけて利用する例。
// factorialは関数の外から呼び出せる名前
// innerFactは関数の外から呼び出せない名前
const factorial = function innerFact(n) {
if (n === 0) {
return 1;
}
// innerFactを再帰的に呼び出している
return n * innerFact(n - 1);
};
console.log(factorial(3)); // => 6
関数式に名前をつけた場合は 関数の中からのみ 関数名を呼び出すことができる。
[ES2015] Arrow Function
const function_name = () => {
// something to do
return return_value;
};
Arrow で関数を定義できる。(C言語のポインタ参照時に使う矢印とは意味が違う) Arrow Functionには書き方にいくつかのパターンがある。
- 仮引数が1つのときは
()
を省略可能 - 関数の処理が1つの式である場合に、ブロックとreturn文を省略可能
- その式の評価結果を
return
の返り値とする。
- その式の評価結果を
様々な Arrow Function の書き方
const fnA = () => { /* 仮引数がない場合 */ };
const fnB = (x) => { /* 仮引数が1つの時 */ };
const fnC = x => { /* 仮引数が1つのときは()を省略可能 */ };
const fnD = (x, y) => { /* 仮引数が複数の時 */ };
値の返し方
// この2行は一緒
const mulA = x => { return x*x; };
const mulB = x => x*x;
Arrow Functionの特徴として、
- 常に無名関数
this
が静的に決定できるfunction
キーワードと比べて短く書けるnew
できない(コンストラクタ関数ではない)arguments
変数を参照できない
といったものが上げられる。
arrayの中身を全て2倍する関数を function
キーワードとArrow Functionで比べてみる。
const array = [1, 2, 3];
// function版
const doubleArray_f = array.map(function(value) {
return value * 2;
});
// Arrow版
const doubleArray_a = array.map( value => value*2 );
Arrow Functionは引数や処理が1つなら、とか arguments
が使えないとか条件が多い分、人による解釈や実装の違いが生まれにくいという特徴がある。
同じ名前の関数宣言は上書きされる
function
キーワードでの関数っ宣言と var
キーワードを使った関数式のみで発生する。
うーん、エラーにしてほしい、、、
コールバック関数
引数として渡される関数のことをコールバック関数と呼ぶ。コールバック関数を引数として使う関数やメソッドのことを高階関数と呼ぶ。
function 高階関数(コールバック関数) {
コールバック関数();
}
他の言語にもよくありますね。
メソッド
オブジェクトのプロパティである関数をメソッドと呼ぶ。JavaScriptにおいては 関数とメソッドの機能的な違いはない 。
const obj = {
method1: function() {
// functionのメソッド
},
method2: () => {
// Arrow Functionのメソッド
}
};
// 空オブジェクトを作った後で定義することもできる
const obj2 = {};
obj2.method = function() {
};
// メソッドの呼び出し
obj.method();
[ES2015] メソッドの短縮記法
const obj = {
method() {
return "this is method.";
}
};
console.log(obj.method()); // -> "this is method."
この書き方はオブジェクトのメソッドだけではなく、クラスのメソッドと共通の書き方である。 他の言語と同じような書き方だと思う。