JavaScript: 2009年1月アーカイブ
<script>
var a = Math.floor(2.9999);
alert(a); // '2'と表示
</script>
サイ本 第3章 データ型と値
3種類の基本データ型
JavaScriptには、基本データ型が3種類ある。| データ型 | 値の例 |
| 数値 | 3 |
| 文字列 | 'hello' |
| 論理値 | true,false |
また、nullとundefinedという特殊なデータ型がある。
これらは値が1種類しかない。
| データ型 | 値の例 |
| null | null |
| undefined | undefined |
複合データ型
オブジェクトと呼ばれる複合データ型がある。オブジェクトには、配列と関数も含まれる。
逆に、配列と関数は、特殊な振る舞いをするオブジェクトである。
Date,RegExp,Errorなどもオブジェクトである(型ではない)。
サイ本 第2章2.8 予約語
ECMAScript v3で決められている予約語の一覧です。意外と少ないんですね。
case
cache
continue
default
delete
do
else
false
finally
for
function
if
in
instanceof
new
null
return
switch
this
throw
true
try
typeof
var
void
while
with
ifやfunctionはよく使います。
逆に使ったことがないのは、default,delete,finally,instanceof, voidあたり。
今後、意識して使うにしようっと。
使用頻度分析とかしたら面白いかも。
達人プログラマと初心者プログラマの違いがはっきり出るんだろうな。ww
サイ本 第2章2.6 識別子
識別子というのは変数や関数につける名前のことです。$記号を好きな位置で使えるところが特異ですね。
var $ = 1;
var $1 = 2;
var $x = 3
var x$ = 4;
var $$ = 5;
var $$$ = 6;
var $_ = 7;
var _$ = 8;
alert($);
alert($1);
alert($x);
alert(x$);
alert($$);
alert($$$);
alert($_);
alert(_$);
$は、jQueryやprototype.jsで使われていますね。いま気づいたんですが、$_も普通に使えるんですね。
Perlっぽくてよさげです。
サイ本 第2章2.5 コメント
Java,C,C++と同じだそうです。// 行コメント
/* コメント */
/*
複数行に
わたる
コメント
*/
/* ~ */ はネストできない
ネストするとエラーになります。
/*
/* */ ← エラー!!
*/
ほ~知らんかった。JavaScript第5版 第2章2.4セミコロン
文末のセミコロンは必須ではない。a = 3 b = 4 alert(a) alert(b)しかし、セミコロンは入れるように推奨されている。
理由は、JSパーサが勝手にセミコロンを補うので、予期せぬ結果になることがあるため。
悪い例
function x(){
return
true
}
alert(x()); // 'undefined'
これは、
return; true;と解釈されてしまったため。
サイ本を熟読して基本をおさらい中。
サイ本 第2章2.2 大文字と小文字
JavaScriptでは、大文字と小文字は区別される。
alert(1); Alert(1); // エラー
a = 1; A = 2; alert(a); // 1 alert(A); // 2
a = function(){alert(1);}
A = function(){alert(2);}
a(); // 1
A(); // 2
WSH/Jscriptでは?
基本的には上記と同じふるまい。ちょっと変わってるのが、WSHオブジェクトのメソッドでは大文字小文字をどちらでも呼び出せる。
WSH.echo(1); WSH.ECHO(1); WSH.Echo(1); WSH.EchO(1); WSH.eCHo(1);
WSH.Quit(); WSH.QUIT(); WSH.quiT();
コレ全部OK。
何故だかはわからない。また、どういう条件の場合これができるのかも不明。
function funcname(args){ do something}; は var funcname = function(args){ do something}; と等価になる。javascriptを理解するためのたった2つの大切なこと
javascriptを理解するためのたった2つの大切なこと:改
引用元の記事はすばらしい記事ですが、ここは間違いです。
等価だと思っていたらひどい目にあいます。
サイ本 第5版
function文はプログラムの静的な構造を定義するだけなのです。
JavaScriptコードが解析されコンパイルされたときに、関数は定義されます。
どういうことかというと、
function foo( ){ ... }
はコンパイル時に関数が定義されます。var foo = function( ){ ... };
は代入文の実行時に関数が定義されます。その証拠に、
foo();
function foo(){ alert(1) }
はOKですが、foo(); // エラー
var foo = function (){ alert(1) };
はエラーになります。ささいな違いに見えますが、プロトタイプを使うときは要注意です。
プロトタイプを使ったメソッド定義は必ず代入文だからです。
メソッド定義は代入文!!
FireFoxでは下記のようなメソッド定義をしようとすると、何故かエラーになります。(IEでは動きます)function Foo(){ }; // クラス宣言
function Foo.prototype.greet(){ alert('hi') }; // エラー
従って、メソッド定義は代入文で書くことになります。
function Foo(){ }; // クラス宣言
Foo.prototype.greet = function (){ alert('hi') }; // メソッド定義は代入文で
正常に動作するケース
よって、下記のコードは動きます。function Foo(){ };
Foo.prototype.greet = function (){ alert('hi') };
var foo = new Foo();
foo.greet();
これも動きます。
Foo.prototype.greet = function (){ alert('hi') };
function Foo(){ };
var foo = new Foo();
foo.greet();
こんなのもOKです。
Foo.prototype.greet = function (){ alert('hi') };
var foo = new Foo();
foo.greet();
function Foo(){ };
こんなんだって動いちゃいます。
var foo = new Foo();
Foo.prototype.greet = function (){ alert('hi') };
foo.greet();
function Foo(){ };
エラーになるケース
これはエラーです。
var foo = new Foo();
foo.greet();
function Foo(){ };
Foo.prototype.greet = function (){ alert('hi') };
これもエラーです。
var foo = new Foo();
foo.greet();
Foo.prototype.greet = function (){ alert('hi') };
function Foo(){ };
おわかりでしょうか?まとめ
- function foo ( ){..} と var foo = function ( ) {..} は、関数が生成されるタイミングが違う
- プロトタイプによるメソッドの宣言は、代入文である。
- メソッドの代入は、
クラス宣言をした後、かつ、インスタンスからメソッド呼び出しをする前
にやるべし。
クロージャとは
クロージャは、言葉で説明するのが大変難しい概念です。あなたは、自転車の乗り方を、身振り手振りなしで口だけで説明できるでしょうか?
あるいは螺旋(らせん)の形を、文章で説明できるでしょうか?
きっと難しいと思うでしょう。
しかし、自転車に乗ることは誰でもできますし、針金1本あれば、螺旋(らせん)の形を作ることはできるでしょう。
「クロージャ」もこれと同じです。
だから、Wikipediaのこんな解説を見ても落ち込まないでください。
クロージャ (クロージャー、Closure) は、プログラミング言語において引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決する関数のことである。理解できないですよね?
私もそうでした。
クロージャを既に知っている人にしか、この文章は理解できないでしょう。
クロージャを作るのは難しくない
しかし、説明するのは難しくても、作るのは意外と簡単。それがクロージャです。手元にウェブブラザさえあれば、誰でもクロージャは作れます。
準備はいいですか?
これから一緒にクロージャを作りましょう!
目次
- 猿でもわかるクロージャ超入門 1 問題
クロージャを使うと何ができるのか? - 猿でもわかるクロージャ超入門 2 関数の中の関数
Javascriptでは関数の中に関数を作れます。 - 猿でもわかるクロージャ超入門 3 無名関数
匿名はお好き? - 猿でもわかるクロージャ超入門 4 関数を返す関数
関数の戻り値が関数だったなら - 猿でもわかるクロージャ超入門 5 クロージャを作る
あ、できちゃった!
参考になったページ
クロージャを理解する手がかりになったページ
- nothing but ordinary - JavaScript はじめてのクロージャ入門
ここが一番わかりやすかった。 - クロージャとは - はてなキーワード
Wikipediaよりは分かりやすかった。 - JavaScriptクロージャを完全理解!スコープチェインを知る(後編) - page2 - builder by ZDNet Japan
カウンタの例がシンプルでわかりやすかった。 - JavaScript クロージャとレキシカルスコープ - Backstage of theater.js
「内部関数とクロージャはほぼ同義」という説明が、クロージャを理解するヒントになりました。
長いページですが、最初の数十行読むだけで充分よいヒントが得られます。
クロージャを理解した後で読むと目からウロコなページ
- Life is beautiful: Javascriptクイズ(中級者向け):無名関数と実行効率の話
無名関数をどういう場面で使うと効果的かがよくわかった。 - Life is beautiful: Javascript、クロージャを使ったプライベート関数の隠蔽について
クロージャをどういう場面で使うと効果的かかがよくわかった。ほおぉ。まさに目からウロコ。 - クロージャの定義 - Perl入門~サンプルコードによるPerl入門~
Perlにおけるクロージャが良く分かった。シンプルな説明がステキです。
追記①
はてなブックマークでたくさんブックマークいただいたので、さらにわかりやすくなるように書き直しました。「ここが分かりにくい」などありましたら、コメントいただければ幸いです。
ちなみに「螺旋」を文章で説明すると、
「回転しながら回転面に垂直成分のある方向へ上昇する曲線」(Wikipeidaより)
だそうです。www
(2009.12.4)
追記②
Perlのクロージャ入門書きました。[Perl]猿でもわかるクロージャ超入門
クロージャは、理解するよりも作るほうが簡単
前回、「関数を返す関数」をいじって、いきなりクロージャを作ってしまいました。こんなやつです。
<script>
//サンプル5-1
function outer(){
var x = 1; // outerのスコープ内で変数を定義
return function (){ //この関数が「クロージャ」
alert(x); // "関数内関数"の中で、outerスコープの変数を参照。
};
}
var f = outer();
f(); // 1と表示。
</script>
これが何故クロージャなのかというと、次の条件を満たしているからです。
- outerのスコープ内で変数を定義し、
- outerの中に関数(=関数内関数)を作って
- その関数内関数から、先ほどの変数を参照する
何の役に立つのか?
「クロージャが作れたのはいいけど、何がうれしいのか?」
もっともな疑問です。では、先ほどのをちょっと改造したこんなコードを実行してみてください。
<script>
//サンプル5-2
function outer(){
var x = 1;
return function (){
alert(x);
x = x + 1;
};
}
var f = outer();
f(); // 1
f(); // 2
f(); // 3
</script>
あれ?
あれれ?
例の問題が解けちゃいましたね。
問題上のコードでは、1回目のf( )が呼び出された後、変数xの値(=2)が捨てられずに保持されます。
呼び出すたびに、1,2,3,...を返すような関数f()を定義せよ。
f(); // 1 f(); // 2 f(); // 3
そこで2回目のf( )を呼び出すと、先ほどのxの値(=2)を覚えていて、それをalert表示してから、xの値を1増やして3にして、それをまた保持ます。
クロージャを使うと、このように「状態を保持する関数」を作ることができます。
「クロージャはオブジェクトに似ている」というのが実感できたかと思います。
これで、あなたはクロージャを100%理解しました。
最後まで読んでくれてありがとう。
おつかれさまですた。
補足1 無名関数は必須ではない。
サンプル5-2のコードは、他にもいろいろな書き方があります。入門3回目で紹介した「無名関数」を使わなくても、クロージャは作れます。
(しかし実際にはクロージャと一緒に使われることが多いので紹介しました。)
「無名関数」を使わないクロージャ
//サンプル5-3
function outer(){
var x = 1;
function inner(){
alert(x);
x = x + 1;
};
return inner;
}
var f = outer();
f(); // 1
f(); // 2
f(); // 3
補足2 「クロージャ」(Closure)という名前について
英和辞典で調べたら「閉鎖」という意味があるそうです。変数xが、outer関数のスコープ内に閉じ込められて(closed)いて、inner関数以外のどこからも参照できないことに由来するのでしょう(たぶん)。
<script>
//サンプル4-1
function outer(){
var inner = function (){ // 無名関数を定義してinnerに代入
alert("hello");
}
return inner; // inner関数を返す
}
var f = outer(); // outre関数は戻り値としてinner関数を返す。それがfに代入される。
f(); // "hello"と表示。inner() が実行されたのと同じ効果がある。
</script>
outer関数が実行されると、
- outer内で無名関数が生成される
- それが変数innerに代入される
- そのinnerが戻り値として返される
- それがfに代入される
「関数を返す関数」
となっています。
「お母さんの胎内から赤ん坊が生まれて、"F"と名づけられ、"F"が"おぎゃあ"と泣いた」みたいな感じです。(変?)
同じことをやるのに、何通りかの書き方があります。
普通に関数を宣言してそれを返す
<script>
//サンプル4-2
function outer(){
function inner(){ // inner関数を定義
alert("hello");
}
return inner; // inner関数を返す
}
var f = outer(); // inner関数がfに代入される。
f(); // "hello"と表示。
<・script>
function inner( )という風に関数innerを宣言しておきながら、return innerという風にinnerを変数のように扱っていて、実に気持ちが悪いですね。innerは関数でもあり、変数でもあるのです。Javscriptにおける関数の2面性をよく表しています。
無名関数を定義してそのままreturnする
<script>
//サンプル4-3
function outer(){
return function (){ // 無名関数を定義してすぐreturn
alert("hello");
};
}
var f = outer(); // onter内で定義した無名関数がfに代入される。
f(); // "hello"と表示。
<・script>
この例では、innerという文字が登場しません。無名関数を使うとコードがとてもすっきりしますね。
さて、"hello"という文字列を事前に準備してみましょう。 上のサンプル4-3と本質的に何ら変わりないコードです。
<script>
//サンプル4-4
function outer(){
return function (){
var x = "hello";
alert(x);
};
}
var f = outer();
f(); // "hello"と表示。
</script>
では次に、var x = "hello"の位置をちょっと外にずらしてみましょう。
<script>
//サンプル4-5
function outer(){
var x = "hello";
return function (){
alert(x);
};
}
var f = outer();
f(); // "hello"と表示。
</script>
問題なく"hello"と表示されましたね。実は、これがクロージャなんです。
クロージャデビュー、おめでとう!!\(^o^)/
これであなたはクロージャを90%理解したことになります。
あと1歩!
次の記事 猿でもわかるクロージャ超入門 5 クロージャを作る
関数を定義する方法その1 (普通のやり方)
<script>
function speak(){ alert("hello"); }
speak(); // "hello"と出力
</script>
はい、普通ですね。次はJS特有のやり方です。
関数を定義する方法その2 (無名関数を使う)
<script>
var speak = function (){ alert("hello"); }
speak(); // "hello"と出力
</script>
2行目に注目。この式の右辺、function( ){...}の部分を無名関数といいます。
右辺で無名関数を生成して、それを変数speakに代入しています。
こうすると、変数speakはまるで関数のような振る舞いをします。(というか関数になります)
speak( )と括弧をつけてやることで、関数呼び出しを実現できます。
方法1と方法2は、ほぼ同じことをしていると考えて結構です。(注2)
無名関数を定義してすぐさま実行する
上記の方法2では、3つのステップを踏んでいます。- 無名関数を定義する
- それを変数speakに代入する
- speak( )で関数を実行する
実はこのステップは省けるんです。
<script>
( function(){ alert("hello"); } )(); // "hello"と出力
</script>
これで、一時変数speakを省くことができました。このように、無名関数を定義してすぐさま実行したいときは
( function( ){..} )( );
という構文になります。
( function......... )( );
の左の括弧が何故必要なのか理解に苦しむところですが、これがないとエラーになります。
まあこういうものだと思ってください。(JSの次期バージョンでは不要になるらしいです)
このような無名関数の構文は、クロージャを実現するときによく使われます。
これでクロージャを60%ぐらい理解したことになります。
クロージャマスターまでだいぶ近づきました。(w
次の記事 猿でもわかるクロージャ超入門 4 関数を返す関数
注1:本当は2通り以上ある。
注2:厳密にはちょっとだけ違います。
クロージャとは関数である。
ずばり言います。クロージャとは、関数である
まずココがポイント。次に、たいていの場合、
クロージャとは関数の中の関数である
これで、クロージャのことを30%程度は理解したことになります。だから、
「クロージャーって何?」
って誰かに聞かれたら、
「ああ、関数の中に書く関数のことでしょ」
って答えとけば、30%ぐらい正解ということになります。(w
関数の中の関数
Javascriptでは、関数の中に関数を書くことができます。もうちょっと正確に言うと、関数の中で別の関数を定義することができます。
//関数の中で関数を定義
function outer(){
function inner(){
alert("hello");
}
}
ここで、関数innerを呼び出すにはどうしたらいいでしょうか?下記のコードをコピペして、デスクトップに.htmlファイルとして保存して、ブラウザで開いてみてください。
<script>
function outer(){
function inner(){
alert("hello");
}
}
inner(); // エラー!
</script>
これはエラーになるか、もしくは何も表示されません。innerはouter関数の中だけで通用するローカルな名前であって、 グローバル空間でinnerは定義されていないからです。
ではやり方を変えてみましょう。
<script>
function outer(){
function inner(){
alert("hello");
}
}
outer(); // 何も起こらない!
</script>
これは、エラーにはなりませんが、やはり何も表示されません。outer( )は実行されたものの、outer内のinnerは宣言されただけで実行(呼び出し)されていないからです。
innerを実行するには、outer内でinner( )を明示的に実行してやる必要があります。
<script>
function outer(){
function inner(){
alert("hello");
}
inner(); //←コレ
}
outer(); // "hello"と表示された!
</script>
おめでとうございます。見事"hello"が表示されましたね。
outer( )が呼び出されたとき、outer内でまずinnerが宣言され、その直後にinner( )が実行されたのです。
これで、あなたはクロージャを30%程度理解したことになります。
「関数の中の関数」をもうちょっと進化させると、クロージャを作ることができます。
でももうちょっとだけ辛抱してください。
その前に、あと2つ別のテクニックを覚える必要があります。
次の記事 猿でもわかるクロージャ超入門 3 無名関数
問題です。
問題: 呼び出すたびに、1,2,3,...を返すような関数 f( )を定義せよ。f(); // 1
f(); // 2
f(); // 3
この問題、解けますでしょうか?
普通の関数では、できないと思います。
しかし「クロージャ」というのを使えば、このようなことができます。
クロージャって何だ?
「クロージャ」という言葉を、プログラムの本やサイトで目にすることがありますよね。私が最初に見たのは続・初めてのPerl 改訂版(アルパカ本)でした。
まったく理解できませんでした。
その後、404 Blog not foundやnaoyaさんのブログなどで「クロージャ」という単語を目にしました。
やはり、まったく分かりませんでした。
とどめの一撃はWikipediaの解説記事。
クロージャ (クロージャー、Closure) は、プログラミング言語において引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決する関数のことである。
本当にありがとうございました(涙)
私はあきらめました。
そして歳月は流れ・・・
最近、Javascriptで勉強してみたら、突然理解できるようになりました。
理解した、というよりも「クロージャが作れてしまった」のです。
上に書いた問題が解けてしまったのです。
「よくわかんねーけど、おれ、自転車に乗れてるぞ?」という、少年のような気持ちでした。
そこで、
「クロージャ」がまったく意味不明だった私がクロージャを作れるようになった過程
を、ここに披露いたします。(注)
私がクロージャを理解するために格闘して、わかったことは、
クロージャは理解するより作るほうが簡単。
クロージャを作るためには、次の3つのことだけできればよい。
ということでした。クロージャを作成するために必要な3つのこと
- 関数内の関数
- 関数を返す関数
- 無名関数
クロージャを作ってからクロージャを理解する。
理解するよりも、作る方が簡単。
これがポイントです。
次の記事 猿でもわかるクロージャ超入門 2 関数の中の関数
まとめ記事 [JavaScript] 猿でもわかるクロージャ超入門 まとめ
注1:理解できるようにはなったが、活用できてない自分がいるのは内緒です。
概要
任意のフォルダの、サブフォルダのサブフォルダ(サブサブフォルダ?)をリスト化して出力します。ダウンロード
getSubSubFolders.js使い方
スクリプトをc:¥getSubSubFolders.jsなどと保存して、コマンドプロンプトで、
c:¥>cscript getSubSubFolders.js //nologo
と入力すればOK。
実行結果の例
C:¥>cscript getSubSubFolders.js c:¥perl //nologo
cpan build
cpan sources
eg aspSamples
eg cgi
eg fork
eg IEExamples
eg PerlEx
eg Windows Script Components
eg Windows Script Host
html bin
html Components
html faq
・・・
長いので以下略
スクリプトのソースコード
var fso = new ActiveXObject("Scripting.FileSystemObject");
var path = argv(0);
var root = fso.getFolder(path);
var subs = getSubFolders(root);
var subsubs=[];
foreach(subs, function(sub){ subsubs = subsubs.concat(getSubFolders(sub)); });
foreach(subsubs, function($_){ echo($_.ParentFolder.Name + "\t" + $_.Name); });
//サブフォルダ一覧を取得
function getSubFolders(oFolder) {
return collectionToArray(oFolder.SubFolders);
}
//コレクションを配列に変換
function collectionToArray(collection){
var objEnu = new Enumerator(collection);
var array = [];
for (; !objEnu.atEnd(); objEnu.moveNext() ){
array.push(objEnu.item());
}
return array;
}
function echo(str) { WSH.Echo(str); }
function argv(i){
if(WSH.Arguments.length == 0) echo('引数が指定されていません。');
return WSH.Arguments(i);
}
function foreach(array,func){ for(var i in array) func(array[i]); }