複数の戻り値を個別の変数に代入する
「関数から複数の値を返す」ためには、配列/オブジェクトとして値を一つにまとめる方法があります。
そのような場合には、
function getMaxMin(...nums) {
//配列で返す
return [Math.Max(...nums), Math.Min(...nums)]
}
//分割代入
let [Max, Min] = getMaxMin(1,2,3,4,5)
//Maxがいらない場合(最大値は切り捨てられる)
let [, Min]
タグ付きテンプレート文字列
変数を埋め込む際に「<」「>」などの文字列を「<」「>」に置き換えたい(エスケープしたい)ときに、役立つのがタグ付きテンプレート文字列です。
タグ付きテンプレート文字列の実態は、単なる関数呼び出しでしかありません。
関数名`テンプレート文字列`
の形式で呼び出されます。タグ付きテンプレート文字列で利用するためには、関数は次のような条件を満たしておく必要があります。
1. 引数として「テンプレート文字列(分解したもの)」と「埋め込み変数(可変長引数)」を受け取る
2. 戻り値として加工済みの文字列を返すこと
たとえば、
//エスケープ処理
function escapeHTML(str) {
if(!str) {return ''}
str = str.replace(/&/g, '&')
str = str.replace(/</g, '<')
str = str.replace(/>/g, '>')
str = str.replace(/"/g, '"')
str = str.replace(/'/g, ''')
return str
}
//タグ付きテンプレート文字列
function e(templates, ...values) {
let result = ''
for(let i = 0, len = templates.length; i < len; i++) {
result += templates[i] + escapHTML(values[i])
}
return result
}
let name = '<"Satou" & \'Saitou\'>'
console.log(e`こんにちは、${name}達!`)
クロージャ
クロージャとは、「ローカル変数を参照している関数ない関数」のことである。
たとえば、
function closure(init) {
let counter = init
return function() {
return ++counter
}
let myClosure = closure(1)
conosle.log(myCLosure()) //2
conosle.log(myCLosure()) //3
conosle.log(myCLosure()) //4
}
一見するとclosure関数は「初期値としてinitを受け取り、それをインクリメントした結果を返している」よに見えます。しかしよく見ると、戻り値は数値ではなく「関数」になっていることがわかります。
この匿名関数を返しているということによって、closure関数の終了後もローカル変数counterは保持されるため「一種の記憶域を提供するしくみ」と考えることができる。
よってこのようなことも可能である。
function closure(init) {
let counter = init
return function() {
return ++counter
}
let myClosure1 = closure(1)
let myClosure2 = closure(100)
conosle.log(myCLosure1()) //2
conosle.log(myCLosure2()) //101
conosle.log(myCLosure1()) //3
conosle.log(myCLosure2()) //102
}
closure関数の同じcounter変数を参照しているのにも関わらず、異なる変数を参照しているかのようにふるまうのである。ここではスコープチェーンという考え方が用いられており、javascriptでは、このスコープチェーンの先頭つまり最内側の関数に位置するオブジェクトから順にプロパティを参照するため、もともとが同じ変数であっても違う値を個々に保持している現象があってもおかしくないのである。
参考資料
山田祥寛様 「javascript本格入門」