完璧な個人的メモです。
何事も基礎は大事だ。
なんとなく理解した気になっているjsの基礎をおさらいしておこうと思った。
即時関数
> (function fact(n) {
... if(n<=1) return 1
... return n*fact(n-1)
... })(5)
// 120
以上のように無名関数を即時実行できる。
ES6の現代では使わないが、面白い。
引数の省略
関数定義式の仮引数よりも少ない数の実引数を指定して関数を実行すると、実引数が省略された仮引数はundefinedが渡される。
> const lol = (x,y) => {
... console.log(x)
... console.log(y)
... }
undefined
> lol("lol")
lol
可変長配列引数リスト(Arugumentsオブジェクト)
(ES6のアロー構文だとarugumentsオブジェクトは使えないが...)
全ての関数で利用可能なローカル変数として、argumentsがあります。arugumentsはArgumentsオブジェクトを値として持っています、関数がn個の実引数を指定して呼び出されたとすると、以下のように実引数の値がarugumentsに渡されます。
arguments[0] 一番目の実引数の値
arguments[n-1] n番目の実引数の値
さらにargumentsオブジェクトはlengthとcalleの2つのプロパティを持っており、次の値が格納されます。
arguments.length ...実引数の数
arguments.callee ...現在実行されている関数への参照
関数の中でargumentsを変更すると、関数の仮引数も変更されます。
ES6では代わりに残余引数を使います。
残余引数
関数の引数リストの最後の引数の前に...をつけると、最後の引数には、実際に関数に渡された実引数の残りの引数が配列として格納されます。この...の付いた引数を残余引数と言います。
const f = (a, b, ...args) => {
console.log(a, b, args)
}
f(1, 2, 3, 4, 5556) // => 1 2 [ 3, 4, 5556 ]
配列として渡されるのがミソ
const sum = (...args) => {
for(var i=0, s=0; i<args.length; i++) s+=args[i];
console.log(s)
}
sum(1,2,3,4,5)
forEach
forEachメソッドは、配列の要素を順番に取り出して、その値を引数の関数に渡すというイテレーションを行います。
const a = [5, 4, 3]
a.forEach(val => console.log(val))
// 5
// 4
// 3
const a = [5, 4, 3]
for(var v of a) console.log(v) // => 5 4 3
for(var v of "ABC") console.log(v) // => A B C
再帰関数
関数から自分自身を呼ぶことを、再帰呼び出しといいます。再帰呼び出しを行う関数を再帰関数と言います。
> const fact = n => {
... if(n<=1) {
..... return 1
..... }
... return n*fact(n-1)
... }
undefined
> fact(5)
120
大抵の場合はfor文やwhile文で書いた方が可読性が高く、高速に動く。
再帰関数でクイックソートを書いてみた。
// x:ソートする配列
// first:ソートする要素の開始位置
// last:ソートする要素の終了位置
const quicksort = (x,first,last) => {
var p = x[Math.floor((first+last) / 2)]
for(var i=first, j=last; ; i++, j--) {
while(x[i]<p)i++
while(p<x[j])j++
if(i>=j) break;
var w = x[i]; x[i] = x[j]; x[j] = w;
}
if (first < i-1) quicksort(x,first,i-1);
if (j+1<last) quicksort(x,j+1,last);
}
var a = [7,2,5,1,8,9,3]
quicksort(a,0,a.length-1)
console.log(a)
上のコードは動かない.あとでなおす
クロージャ
クロージャの定義は
「自分自身が定義された環境において、関数内の自由変数の名前解決を行う」
何言ってるかわからないですね。要約すると、関数自身の外側のスコープに変数名を探しに行くみたいです。
function makeCounter() {
var count = 0
return function() {
return count++
}
}
みたいな感じらしい。ES6でのカリー化と何が違うのだろうか?
ちなみにカリー化すると
const makeCounter = (a) => (b) => {
return a + b
}
const counter = makeCounter("lol")
console.log(counter("ol")) // => lolol
となる。...reduxのミドルウェアを作る時以外見ないが
clojureで実装できる関数ファクトリという機能はカリー化では以下のように定義出来る
const makeMultiplier = x => y => x + y
const multi1 = makeMultiplier(2) // => 4
const multi2 = makeMultiplier(10) // => 13
console.log(multi1(2))
console.log(multi2(3))
おまけ
jsって1行でif文が書けるのね。驚いた。
if (1==1) foo
while(condition) i++