みこむらめもむらむらむら

なんかHTML5とかJS勉強とかやりながらめもを綴るブログ

2012-05-02

【JavaScript】字句構造

やばいな、ひさびさすぎてはてな記法忘れているぞw

ということで再びお勉強→ここにまとめの流れでやっていくよ

JavaScript 第5版

サイ本、やります!

この一ヶ月で読破‥
逆算してみると結構既に焦らないとまずい状態なので
精いっぱい勉強していくことにするよ

ここにまとめるのは2章からにするある
1章は概要だったので

さて、がんばるぞー

字句構造とは

(・∀・)<そもそもじくこうぞうなんてはじめてききました!

プログラムの記述方法を規定する基礎的ルールの集まりのことを
プログラム言語の字句構造というそうな、ふむ‥

たとえば

  • 変数名の表記法
  • コメントに使用する文字
  • 複数のプログラム文の区切り方

などを規定するもの、なるほど文法とかそういう類の言葉ねはあく!

文字コード

JavaScriptプログラムはUnicode文字を使って記述する

大文字と小文字

JavaScriptでは大文字と小文字を区別する
これはもうおなじみです(・∀・)

キーワード、変数、関数名、識別子で大文字と小文字が厳密に区別される


【JavaScript】基本的な記法
「文(Statement)のルール」のとこでもやってますね

HTMLではタグや属性で小文字大文字が区別されないが
JavaScriptで記述するときは
イベントハンドラも含め、全て小文字表記で記述するべし(・∀・)べし!

セミコロン

JavaScriptの文は最後にセミコロン(;)を入れる
これももうおなじみです(・∀・)

同じく【JavaScript】基本的な記法
「文(Statement)のルール」のとこでもやってますね

コメント

これも本当におなじみです(・∀・)

【JavaScript】基本的な記法
「コメントを入れる」のとこでもやってますね

リテラル

JavaScriptでプログラムに直接記述するデータ値のことをリテラルと呼ぶ

もう一個の技術書では
>>データ型に格納できる値そのものをリテラルという<<
ってなってたなー

これは【JavaScript】データ型の記事
リテラル」ってとこで振りかえれまする

この技術書ではまたあとで細かい解説があるみたいなので
また後程













ていうかここまで来て思うけど想像以上に復習なため
ただのリンク集になる件‥うーんしばらくまとめ書かなくていいかも
ちょっと読む方に集中してみる

2012-04-25

【ぼやき】どうやっても高度な関数のテーマ②がうまいことまとめられない件

たぶん理解しきってないから
消化不良のままでうまいこと書けないのだと思う

ということでサボっているわけではないのですよ
いやサボってるといえばサボっているけれども‥小声

ここだけの話、業務時間の8割を
ゲームして過ごしていたここ一ヶ月
死んだ方がいいのはわかっている、云わないで

ちょっといい加減に危機感を覚えないとまずい

このままじゃ査定下がる‥切実
ということでちょっと目標を立ててみた

  • 5月
    • 技術書2冊読破
    • なんとなくでもわかるようにする
  • 6月
    • すでに業務で書いたjQueryJavaScriptで書き直すとかやってみる
    • 既存のScriptをわからないなりに読んでみる
  • 7月
    • なんか自分で作ってみる
    • これ継続して毎月頑張るとかしないとだめだよなー‥知ってる
  • 8月
    • 簡単な作業は一人で十分!
  • 9月
    • 隣の席のYさんくらいになる(無謀)

結構無謀だけどこれくらいの必死さは必要だと思うの


以下5月に読もうと思ってる技術書

JavaScript本格入門 ~モダンスタイルによる基礎からAjax・jQueryまで
こっちはあと半分くらい読んでないので
最後までとりあえず読む
なんかこの章はやらなくてもいいよと言われている部分が
多々あるのだけれどとりあえずやるだけやる
無駄じゃないはず

JavaScript 第5版
こっちはおなじみオライリーですね、サイ本
なんかねJavaScript本格入門でやったけど曖昧、みたいなとことたくさんあるし
でももう一度JavaScript本格入門を頭から読むっていうのも結構しんどいし
ていうか読んでもぬるぬるになっちゃう自分がいて
なんとかしないとと思っていたのでちょうどいいかなと

ということでがんばります

早速ですがJavaScript本格入門は現在詰んでるので
今日からサイ本読んでみます

カフェいって集中してやるんだがんばるんだ

ということで宣言したので、やりまする

2012-04-12

【ぼやき】なんかなんとなくいきています、あかん

だめだ、なんとなく生きているだけになってて
全然意識が変わってしまっている‥
あかーん!
ということでちょっと改めてブログを書きにきたよ

最近はSPページのコーディングやったり
jQueryつかってみたり
簡単なjs書いたりしてました、業務で
全然気づきや勉強したことをまとめてないからいけないんだね
そうだね、しってる

なんかねモバマスが全部悪い気がしている
狂わせている私の生活を
自覚はあるのでとりあえず会社に着いたら
iPhoneの電源を切ろうかーあーやだーきりたくないー←

ということでちょっとがんばります、ふたたび

もうすぐ今期の目標設定なので
それまでに半年後どうなっていたいかを
ちょっとでもイメージしておかないと‥ひー

とりあえずjQueryつかってあれこれやったのを
jQueryじゃなかったらどれだけ大変かとか
そういうのわかるようにしよう、うん

改めてテキスト読み直すところから、さーてやるぞー

2012-02-08

【CSS3】ドロップシャドウやグロー(光彩)をCSSで(box-shadow)

これも折角だから改めて調べてみためもめも
ちゃんとAndriod、iPhoneで確認もした!
問題なく表示されたのぜ!(・∀・)

ドロップシャドウ(box-shadow)の基本的な書き方

「box-shadow」は名前の通りボックスに影をつけてくれるプロパティ

省略形が存在するので記述方法にはいくつかパターンがあるけど
まずは基本形から(・∀・)

box-shadow: 3px 3px 5px 0 #777;
box-shadow:横方向のずれ 横方向のずれ ぼかしの大きさ 影の広がり 影の色;

てな感じで指定できる!

  • ぼかしの大きさ
    • 値が大きい程ぼんやり、値が小さい程くっきり
  • 影の広がり
    • シャドウ全体の大きさの拡張・縮小
    • 「ぼかし部分の内側に作られるpadding」というイメージ
    • 負の値を設定することも可能

4つ目の値を省略すると影の広がりが0pxなのと同じ表示に
3つ目、4つ目の値を省略するとぼかしの大きさが0px扱いになり
くっきりした影になりますのぜ
ちなみに数値1つでは動作しません

実際に使用するときはこんな感じで‥

.shadow{
  -webkit-box-shadow: 3px 3px 5px 0 #777; /* Safari, Chrome用 */
  -moz-box-shadow: 3px 3px 5px 0 #777; /* Firefox用 */
  box-shadow: 3px 3px 5px 0 #777; /* CSS3 */
}

これ便利ねー

ちなみに光彩は!

おわかりかもしれませんが
横方向のずれ、横方向のずれを0にすると実現できるのぜ

.shadow{
  -webkit-box-shadow: 0 0 5px 0 #777; /* Safari, Chrome用 */
  -moz-box-shadow: 0 0 5px 0 #777; /* Firefox用 */
  box-shadow: 0 0 5px 0 #777; /* CSS3 */
}

更に内側のシャドウも(inset)

「inset」という値を追加するだけ!

.shadow{
  -webkit-box-shadow: inset 3px 3px 5px 0 #777; /* Safari, Chrome用 */
  -moz-box-shadow: inset 3px 3px 5px 0 #777; /* Firefox用 */
  box-shadow: inset 3px 3px 5px 0 #777; /* CSS3 */
}

きゃーかんたーん!(・∀・)

更にさらに複数のシャドウも

値を「,」で区切ることで複数のシャドウを設定することが可能なのぜ

なにそれ複数ってどういうこと?ってなった方
影の外にさらに影、みたいになります

.shadow{
  -webkit-box-shadow: 0 0 4px 0 #F00, 0 0 12px 0 #777, 5px 5px 5px 0 #777;
  -moz-box-shadow:  0 0 4px 0 #F00, 0 0 12px 0 #777, 5px 5px 5px 0 #777;
  box-shadow:  0 0 4px 0 #F00, 0 0 12px 0 #777, 5px 5px 5px 0 #777;
}

あと外側の影+内側の影なんてのもできる

.shadow{
  -webkit-box-shadow: 3px 3px 5px 0 #777, inset 0 0 10px 0 #fff;
  -moz-box-shadow: 3px 3px 5px 0 #777, inset 0 0 10px 0 #fff;
  box-shadow: 3px 3px 5px 0 #777, inset 0 0 10px 0 #fff;
}

これつかえばボタンとかCSSでなんとかなっちゃうね、すごいね

2012-02-08

【Android】【iPhone】viewport

久しぶりにスマホページのコーディング依頼があったので
JavaScriptのお勉強を一旦お休みしてSPページ関連のメモをかくよ

今更だけどちゃんと調べたのでviewport

viewportとは

  • ウィンドウのサイズのようなもの
  • 初期値は横幅980pxに指定されている
    • ちなみにiPhoneの横幅は320px、約3倍の幅が指定されてる
    • この初期値が指定されているからPCページをスマホで見ると縮小された状態で表示される

ふむふむ、なるほどですね

viewportの指定方法

metaタグで指定する

<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
プロパティ 説明 初期値 許容範囲 備考
width デバイスの横幅 980px 200~10,000px device-width(デバイスの横幅に合わせる)の指定が可能
height デバイスの縦幅 横幅とアスペクト比から計算される値 200~10,000px device-height(デバイスの縦幅に合わせる)の指定が可能
initial-scale ページが最初に読み込まれた時の拡大率 表示範囲から計算される値 minimum-scale~maximum-scale 乗数で指定(例:120%の場合は1.2)
minimum-scale 拡大率の下限 0.25 0~10 乗数で指定
maximum-scale 拡大率の上限 1.6 0~10 乗数で指定
user-scalable ユーザーに拡大縮小を許可するか yes yes or no no(拡大縮小不可)にすることでフォーム入力時のスクロールも不可
  • device-widthはiPhone横持ちの場合でも必ず320pxとなる
  • device-heightはiPhone縦持ちの場合でも必ず480pxとなる

結局どう設定したらいいの?

端末の横幅を最大限に活かすべきなので
特に理由が無ければ大抵の場合は、viewportはdevice-widthに指定
縮小拡大はできないようにしてあるのが普通

あとは臨機応変に

注意点

仕様に関して詳しく検証しているサイトを見つけたので
貼っておくます

http://ipn3g.com/web/study3.html

以下引用

  • コンテンツより小さいviewport width/heightを設定すると無視される
  • viewportでinitial-scaleを設定せずにwidth/heightを設定すると全画面表示となる
  • viewportでinitial-scaleもwidth/heightも設定しないとwidth=980px/height=1091pxとなる
  • 表示域とコンテンツのサイズが一致しない場合にinitial-scaleを設定すると、意図しないレイアウトが発生することがある
2012-02-07

【JavaScript】高度な関数のテーマ①

さてさて関数もここまでやってきました最後の章

関数を利用したより高度なトピックの紹介とのことで
基本を!っていう方は後でもいいよ!ってなってたんだけれど
なんか周りでクロージャクロージャって
よく聞くからやってみることにするよ

補足:名前付き引数でコードを読みやすくする

名前付き引数とは、
呼び出し時に名前を明示的に指定できる引数のこと

triangle ({ base:5; height:4; })
  • 名前付き引数を用いることのメリット
    • 引数が多くなっても、コードの意味が分かりやすい
    • 省略可能な引数をスマートに表現できる
    • 引数の順番を自由に変更できる

名前付き引数を利用すれば先ほどのtriangle関数は
以下のように呼び出すことも可能

triangle ({ height:4; })  //前方の引数だけ省略
triangle ({ height:4; base:5; })  //引数の順番の変更

もちろん呼び出しに際して
明示的に名前を指定しなければならないので
コードが冗長になるというデメリットもあるが

  • そもそも引数の数が多い
  • 省略可能な引数が多く、省略パターンにもさまざまな組み合わせがある

ようなケースには有効な方法である
その時々の文脈に応じて使い分けるようにすること

名前付き引数の具体的実装方法

function triangle(args) {
  if (args.base == undefined) { args.base = 1; }
  if (args.height == undefined) { args.height = 1; }
  return args.base * args.height / 2;
}

document.writeln(triangle({base:5, height:4}));  //10

名前付き引数と云っても何ら難しいものではなく
引数を匿名オブジェクト(ここでは仮引数args)で
受け取っているだけである
メソッドの中でもオブジェクトのプロパティとして
それぞれの引数にアクセスしている点に注意
呼び出しのタイミングでも引数を「{..}」と記述しているのは
匿名オブジェクトを表しているためである

関数の引数も関数(高階関数)

JavaScriptの関数はデータ型の一種」そうね何度もやったね
つまり、関数そのものもまた、他の数値型や文字列型などと同様
関数の引数として渡したり
戻り値として返したりすることができるということ
べんりー(・∀・)
そして、そのように
「関数を引数、戻り値として扱う関数」のことを
高層関数と呼ぶ、うむ

//高階関数arrayWalkを定義
function arrayWalk(data, f) {
  for (var key in data) {
    f(key, data[key]);
  }
}

//配列を処理するためのユーザ定義関数
function showElement(key, value) {
  document.writeln(key + ':' + value);
}

var ary = [1, 2, 4, 8, 16];
arrayWalk(ary, showElement);

0:1
1:2
2:4
3:8
4:16

arrayWalk関数は、引数に与えられた配列dataの内容を
指定されたユーザ定義関数fの規則に従って
順番に処理するための高階関数

さてここでちょっとfor..in命令の復習はさんでいいですかw

配列内の要素を順に処理する(for..in命令)

for(仮変数 in 配列/オブジェクト) {
  ループ内で実行する命令(群)
}
  • 指定された配列/連想配列やオブジェクト配下の要素/メンバに対して先頭から順番に繰り返し処理を行う
  • 仮変数には、配列/連想配列やオブジェクトから取り出された要素のインデックス番号やキー名、メンバ名が格納され、for..inブロックの中で要素値を参照する際に使用することができる
  • 仮変数に格納されるのが要素値そのものではないことに注意
  • for..inループを利用するのは連想配列、オブジェクトのキーを走査する場合に留め通常配列を走査する場合は原則としてforループを利用するようにする
    • for..inループは配列のインデックス番号を取り出すだけなのでコードがあまりシンプルにならない(値そのものではないので、却って誤解を招く)
    • 通常配列の内容を取り出す処理はコードによっては正しく動作しない場合がある

おうおう思い出した順番に取り出してくるやつね
よしわかったところで続き

高階関数arrayWalkにおける引数の意味は

  • data
    • 処理対象の配列
  • f
    • 配列の各要素を処理するためのユーザ定義関数

となっている

なお、ユーザ定義関数fは引数として
配列のキー名(仮引数key)、値(仮引数value)を受け取り
与えられた配列要素に対して任意の処理を行うものとする
(これは高階関数というよりもarrayWalk関数としての決まりである)

えーっと‥?(・∀・;)

ここでは、ユーザ定義関数showElementは与えられた引数に基づいて
「<キー>:<値>」のような形式で出力する
そのため、arrayWalk関数はそれ全体として
配列内のキー名と値をリスト形式で出力することになる

えーっと‥?えーっと‥?(;∀;)

もちろんユーザ定義関数は自由に差し替えることができる

‥‥(・∀・)

ちょっとここまで理解できてないから
一旦次に行かずストップして考える(・∀・)

//高階関数arrayWalkを定義
function arrayWalk(data, f) {
  for (var key in data) {
    f(key, data[key]);
  }
}

//配列を処理するためのユーザ定義関数
function showElement(key, value) {
  document.writeln(key + ':' + value);
}

var ary = [1, 2, 4, 8, 16];
arrayWalk(ary, showElement);
  • arrayWalk関数を実行する
  • 引数ary、showElementを渡す
  • ってことは「function arrayWalk(ary, showElement) {」みたいな
  • ってことは「f(key, data[key]);」⇒「showElement(key, data[key]);」みたいな
  • for..in命令で配列内の要素を順に処理する
  • そのたびにshowElementも実行される
  • 「document.writeln(key + ':' + value);」される
    • ここの引数keyは「f(key, data[key]);」のkeyが代入されたものか?

あーあーわかった
引数がkeyばっかりだから
なにがなんだかわからないんだ

書きなおしてみた

//高階関数arrayWalkを定義
function arrayWalk(data, f) {
  for (var key1 in data) {
    f(key1, data[key1]);
  }
}

//配列を処理するためのユーザ定義関数
function showElement(key2, value) {
  document.writeln(key2 + ':' + value);
}

var ary = [1, 2, 4, 8, 16];
arrayWalk(ary, showElement);

はあく!

じゃあ続き!

もちろんユーザ定義関数は自由に差し替えることができる

//高階関数arrayWalkを定義
function arrayWalk(data, f) {
  for (var key in data) {
    f(key, data[key]);
  }
}

//配列を処理するためのユーザ定義関数
var result = 0;
function sumElement(key, value) {
  result += value;  //与えられた配列要素でresultを加算
}

var ary = [1, 2, 4, 8, 16];
arrayWalk(ary, sumElement);
document.writeln('合計値:' + result);

合計値:31

ユーザ定義関数sumElementは与えられた値valueを
グローバル変数resultに足しこんでいる
(ここでは引数keyは使用しない)
そのため、arrayWalk関数はそれ自体として
配列要素の合計値を求めることになる

ここでおおもとのarrayWalk関数は
一切書き換えていない点に注目
このように高階関数を利用することで
ベースとなる機能はそのまま
(ここでは配列の内容を順番に取り出すこと)に
具体的な処理内容だけを自由に差し替えることができる
ふむーなるほどー

さっきの二つを私なりに書きなおしてみると
こんな感じかな?

//高階関数arrayWalkを定義
function arrayWalk(data, f) {
  for (var key1 in data) {
    f(key1, data[key1]);
  }
}

//配列を処理するためのユーザ定義関数①
function showElement(key2, value) {
  document.writeln(key2 + ':' + value);
}
//配列を処理するためのユーザ定義関数②
var result = 0;
function sumElement(key2, value) {
  result += value;  //与えられた配列要素でresultを加算
}

var ary = [1, 2, 4, 8, 16];
arrayWalk(ary, showElement);  //ユーザ定義関数①呼び出し
arrayWalk(ary, sumElement);  //ユーザ定義関数②呼び出し
document.writeln('合計値:' + result);

0:1
1:2
2:4
3:8
4:16
合計値:31

二つ並べても問題ない、ってことですな、べんり!
keyのあたり分かりにくいから
わざと引数名変えていますです(・∀・)
私がばかなだけなんだけれども

「使い捨ての関数」は匿名関数で

匿名関数と高階関数は密接な関係を持っている、とな
というのも、高階関数においては引数として与えられる関数が
「その場限り」でしか利用されないことがよくあるため
このような「使い捨ての関数」は
あえて名前付きの関数として定義するよりも
匿名関数(関数リテラル)として記述した方がコードがシンプルになる

//高階関数arrayWalkを定義
function arrayWalk(data, f) {
  for (var key1 in data) {
    f(key1, data[key1]);
  }
}

var ary = [1, 2, 4, 8, 16];
arrayWalk(
  ary, 
  function(key2, value) {
    document.writeln(key2 + ':' + value);
  }
);

さっきのshowElement関数を匿名関数で書き換えたもの

匿名関数(関数リテラル)を利用することで
関数呼び出しコードに関数を直接指定することができる
このような記法は下記のようなメリットがある

  • コードが短くなる
  • 関連する処理が一つの文で記述できるため、呼び出し元のコードと実際の処理を規定している関数との関係がわかりやすくなる
  • 一度限りしか利用しない関数に名前(しかもグローバルスコープの名前)を付けずにすむため、「意図せぬ名前の重複を回避できる」

今後より高度なスクリプト(特にAjaxのコールバック関数)を
記述する上で重宝する
また、多くのJavaScriptプログラマが好んで利用しているので
外部ライブラリなどを読み解く際にも有効、ふむー






まだもう少し高度な~続きそうなので記事分けよう

2012-02-06

【JavaScript】引数情報を管理する(argumentsオブジェクト)

JabaScriptは引数の数をチェックしない

function showMessage(value) {
  document.writeln(value);
}

showMessage();  //undefined
showMessage('山田');  //山田
showMessage('山田', '鈴木');  //山田

ユーザ定義関数ShowMessageは引数をひとつ受け取る

このような関数に対して上記コードのように
それぞれ0、1、2個の引数を渡してやると
0個、2個の場合エラーが出るように感じるが
実際は正しく動作する

JavaScriptでは
与える引数の数が関数側で要求する数と異なる場合も
これをチェックしない

したがって引数0個の場合、仮引数valueの値は
undefined(未定義)であるものとして処理される
また、引数が多かった場合、多かった2つ目の引数('鈴木')は
とりあえず無視され結果として
引数を1個渡した場合と同様の結果が得られた
もっとも多かった引数は切り捨てられるわけではない
内部的には「引数情報のひとつ」として保持されて
あとからりようできる状態になっている
この引数情報を管理するのがargumentオブジェクトである
argumentオブジェクトは関数配下(関数を定義する本体部分)でのみ
利用できる特別なオブジェクトである

argumentオブジェクトは関数呼び出しのタイミングで生成されて
呼び出し元から与えられた引数の値を保持する
このargumentオブジェクトを利用することで、たとえば
「実際に与えられた引数の数と要求する引数の数を比較し、
異なる場合にはエラーを返す」といった処理も記述できる

function showMessage(value) {
  if (arguments.length != 1) {
    throw new Error('引数の数が違うのぜ(・∀・)' + arguments.length + '個じゃ多いのだわ');
  }
  document.writeln(value);
}

try {
  showMessage('山田', '鈴木');

} catch(e) {
  window.alert(e.message);
}

あれ?try..catch命令とかthrow命令って
どんなだっけってなったので復習

例外処理(try..catch..finally命令)

try {
  例外が発生するかもしれない命令(群)
} catch(例外情報を受け取る変数) {
  例外が発生した際に実行する命令(群)
} [finally {
  例外の有無に関わらず、査収的に実行される命令(群)
}]
  • 例外情報はcatchブロックにErrorオブジェクトとして引き渡される
throw new Error(エラーメッセージ)
  • 例外はプログラム中に発生したものを補足するばかりではなく自分で発生させることもできる
  • 例外を発生させることを「例外をスローする」ともいう
  • throw命令は多くの場合if命令のような条件分岐命令と一緒に使用される

うむ、そうでしたこんなんやりました

この例で注目すべきはif命令のあたり
lengthは、argumentsオブジェクトに属するプロパティの一つで
実際に関数に渡された引数の個数を表す
つまりここでは
「実際に渡された引数が1個でない場合に例外をスローしている」
のである
例では呼び出し元の引数が2個なので例外が発生し
エラーメッセージをダイアログ表示する

ここでは、単に日引数の個数をチェックしているだけだが
引数のデータ型や値の有効範囲などの妥当性をチェックすることもできる

argumentsとArgumentsどちらが正しい?

argumentsオブジェクトの実体は、厳密には
「Argumentsオブジェクトを参照するargumentsプロパティ」である
入門書によってはArgumentsオブジェクトと記載されているものも多い
しかし、関数のなかで「Arguments.length」と記述することはできない
Argumentsオブジェクトはあくまで関数内で暗黙的に生成されるもので
プログラマが意識することすらない存在である
なるほどー
この本では混乱しないように
argumentsオブジェクトという記述で統一しているみたいね、ふむ

補足:引数のデフォルト値を設定する

引数の数をチェックしない、ということはJavaScriptでは
すべての引数は省略可能であるということになる
ただし多くのケースでは、引数がただ省略されただけでは
正しく動作しないことがほとんどである

デフォルトで引数を設定しておく必要がある

function triangle(base, height) {
  if (base == undefined) { base = 1; }
  if (height == undefined) { height = 1; }
  return base * height / 2;
}

document.writeln(triangle(5));  //2.5

上記のtriangle関数において引数base、heightのデフォルト値はいずれも1である

JavaScriptでは、引数のデフォルト値を表現するための構文はない
そのため、例のように引数の内容をチェックし
undefined(未定義値)だった場合にそれぞれの値をセットしている

「document.writeln(triangle(5));」では引数が一つしか設定されていない
そのため、後方の引数heightが省略されているものとみなされ
「5×1÷2」で2.5という結果が得られる
引数baseだけを省略することはできない
「省略できるのは、あくまで後ろの引数だけである」という点に注意

可変長引数の関数を定義する

argumentsオブジェクトの用途は
なにも引数の妥当性チェックだけにあるわけではない
可変長引数の関数という重要な機能がある

可変長引数の関数とは「引数の個数があらかじめ決まっていない関数」のこと
たとえば、Functionコンストラクタを思い出してみるとわかりやすいかもしれない
Functionコンストラクタでは、生成する関数オブジェクトが
要求する引数の個数に応じて引数を自由に変更できる
Functionコンストラクタでは
生成する関数オブジェクト要求する引数の個数に応じて、引数を自由に変更できる

var showMessage = Function('msg', 'document.writeln(msg);');
//与える引数は2個(仮引数と処理内容が一つずつ)
var triangle = new Function('base', 'height', 'return base * height / 2;');
//与える引数は3個(仮引数が2個と処理内容が一つ)

このように、呼び出し元の都合で引数の個数が変動する可能性がある
宣言時に引数の個数が確定できない関数が可変長引数の関数である

可変数引数の関数を利用することで柔軟に処理を記述することができる
下記は引数に与えられた数値を合計するsum関数を定義する例である

function sum() {
  var result = 0;
    //与えられた引数を順番に取り出し、順に加算処理
  for (var i = 0; i < arguments.length; i++) {
    var tmp = arguments[i];
    if (isNaN(tmp)) {
      throw new Error('指定値が数値じゃないよ' + tmp);
    }
    result += tmp;
  }
  return result;
}

try {
  document.writeln(sum(1, 3, 5, 7, 9));//25

} catch(e) {
  window.alert(e.message);
}

この例ではforループの中でarugmentsオブジェクトから
すべての要素(引数の値)を取り出しその合計値を求める
arugmentsオブジェクトからi番目の要素を取り出すには
「arugments[i]」のように記述する
また、ここではグローバル関数isNaNで
取得した要素が数値であるかどうかを確認している点に要注目である
isNaNがtrueを返す(要素が数値でない)場合には
Errorオブジェクトを呼び出し元にスローし処理を中断する

明示的に宣言された引数と可変長数を混在させる

function printf(format) {
    //引数の2番目以降を順番に処理
  for (var i = 0; i < arguments.length; i++) {
    var pattern = new RegExp('\\{' + (i - 1) + '\\}', 'g');
    format = format.replace(pattern, arguments[i]);
  }
  document.writeln(format);
}

printf('こんにちは、{0}さん、私はみこむらです', '山田', 'みこむら');
//こんにちは、山田さん、私はみこむらです

printf関数は、第1引数で指定された書式文字列に含まれる
プレイスホルダ(パラメータの置き場所:{0}、{1}、{2}..)を
第2引数以降の値で置き換えたものを出力するための関数

printf関数で第1引数だけが仮引数formatとして明示的に宣言されており
第2引数以降がいわゆる可変長引数として扱われている点に注目
このようなケースでもargumentsオブジェクトには
明示的に宣言された引数→可変長引数の順番ですべての引数が格納される
可変長引数だけがargumentsオブジェクトに管理されるわけじゃない点に注意

つまり、ここではargumentsオブジェクトから
可変長引数の部分(arguments[1]..[n])を取り出し
順に対応するプレイスホルダ({0}、{1}、{2}..)と置き換えている

あ、一応replaceメソッドの復習

正規表現で文字列を置き換える

  • String.replaceメソッド
    • 正規表現でマッチした文字列を置換する
    • 置換後の文字列には「$1..$9」といった特殊変数を埋め込める
    • この特殊変数はサブマッチ文字列を保存するための変数
置き換え対象の文字列.replace(正規表現オブジェクト, 置換後の文字列)

うむー何とか意味が理解できた気がする

無名引数は必要最低限に

明示的に宣言された引数に対しては、
変数名formatで直接アクセスするほか
argumentsオブジェクト経由で
「arguments[0]」のようにアクセスすることもできる
つまり先ほどの例のような場合でも(構文的には)
すべての引数を可変長引数として記述できる

しかし、これはコードの可読性という観点から推奨できない
インデックス番号で引数を管理するargumentsオブジェクトよりも
名前で管理する引数の方が
直観的に引数の内容を把握しやすいからである

なにからなにまでargumentsオブジェクトに委ねるのではなく
内容や個数があらかじめ想定できる引数については
できるだけ明示的に名前を付けておくこと

ふむふむ了解である

可変長引数にも仮の名前を付ける

「コードの可読性」という意味では
可変長引数にも仮の名前を付けておくのが望ましい

たとえば先ほどの例だと以下のようになる

function printf(format, var_args) {

これによって後からコードを読んだ人間は
printf関数の末尾に可変長関数を指定できることを理解できる
ただし、この引数var_argsはあくまで便宜的な名前なので
関数の中ではこれまでと同じく
argumentsオブジェクト経由でアクセスする必要がある
(引数var_argsにすべての可変長引数が格納されるわけではない)

再起呼び出しを定義する(calleeプロパティ)

argumentsオブジェクトでもう一つ重要なのが
現在実行中の関数自身を参照するために用意されている
calleeプロパティである
argumentsオブジェクトのその他のプロパティに比べると
calleeプロパティを目にする機会はそれほど多くはない
しかし、calleeプロパティを利用すれば、
関数などの特定の処理の中で自分自身を呼び出す
再帰呼び出し(Recursive Call)の処理を
容易に記述できるようになる
これによりたとえば階乗計算のように
同種の手続きを階層的に何度も呼び出すような処理を
シンプルなコードで表現できる

function factorial(n) {
  if (n != 0) { return n * arguments.callee(n - 1); }
  return 1;
}

document.writeln(factotial(5));  //120

factorial関数は与えられた自然数nの
階乗を求めるためのユーザ定義関数である
ここでは自然数nの階乗が「n×(n-1)!」で
求められることに着目している
これを再帰的に表現しているのが
「return n * arguments.callee(n - 1);」である
つまり与えられた数値から1を差し引いたもので
自分自身を再帰的に呼び出しているのである
冒頭で述べたように、
関数自身を表すのはarguments.calleeプロパティである
これを念頭において先ほどのコードをみてみると
内部的には以下のような手順で処理が行われていることになる

factorial(5)
  → 5 * factorial(4)
    → 5 * 4 * factorial(3)
      → 5 * 4 * 3 * factorial(2)
        → 5 * 4 * 3 * 2 * factorial(1)
          → 5 * 4 * 3 * 2 * 1 * factorial(0)
            → 5 * 4 * 3 * 2 * 1 * 1
          → 5 * 4 * 3 * 2 * 1 
        → 5 * 4 * 3 * 2
      → 5 * 4 * 6
    → 5 * 24
  → 120

このように何段階にわたる処理も再帰呼び出しを利用すれば
これだけ短いコードで記述できる
なお、階乗計算の場合、
自然数nが0である場合に戻り値を1とすること」を
忘れないように気を付ける
さもないとこの再帰呼び出しは無限ループになってしまう

また、この例であれば下記記述を

return n * arguments.callee(n - 1);

calleeプロパティを使わずに以下のように記述することもできる

return n * factorial(n - 1);

しかしこのように記述すると、
もともとの関数名が変更された場合に
関数本体の記述も変更しなければならないことから
あまり好ましくない

また、以下のように匿名関数として記述された場合には、
そもそも再帰呼び出しするための関数名がないため
calleeプロパティを利用「しなければならない」

function (n) {
  if (n != 0) { 
    return n * ???(n - 1);  //←関数名が指定できない
  }
  return 1;
}

document.writeln(factotial(5));  //120

再帰呼び出しとcalleeプロパティ
いずれも重要な事項なので
ここで合わせてきちんと理解する必要がある、うむ

うむ!
使う機会があまり想像できないのでその辺は先生に!