2007/11/30

javascriptを初めて学ぶ人についてのおさらい。その1

ポスト @ 2:23:29 , 修正 @ 2007/11/30 2:40:42 | ,     このエントリーを含むはてなブックマーク

僕にも教える人ができた(? というか人にモノを教える立場)になったので、とりあえず、最近はもっぱらjavascriptを教えています。
もともとCやJavaなどについてはある程度の知識がある人なので、それを少しjs的な意味で、関数言語的な教えをやっている最中のメモ

変数って何ですか?変数って値もしくは式そのものに利便的な名前をつけているものです

次のhogefooは値をいれる箱ではなく、値そのものに別名(もしくは分かりやすい名称)を割り当てているだけに過ぎませんよ。

var hoge = 1;
var foo = [1, 2, 3];

alert(hoge + 1);  // 2
alert(foo[0]);  // 1

alert(1 + 1); // 2
alert([1, 2, 3][0]); // 1

つまり、関数自体を変数に代入する事ができます。(functionとは特別な呼び名ではなく、[](Array)や{}(Object)のような簡単な型名の一つです)
関数はグローバルに置かれる必要はなく、関数さえも変数の一つとして扱えます。

var _eval = eval;
var _alert = window.alert;
var _func = Function;
var lambda = function (){
    alert("hoge");
};  

alert(typeof _eval); // function
alert(typeof _alert); // function
alert(typeof _func); // function
alert(typeof lambda); // function

"("から")" は実行するための目印です。引数はその中に書く事ができます。applyやcallという別名もあります。

関数を受け取った変数であっても、()を使う事で呼び出しを行うことができます。

var test1 = function (){
    alert("hoge");
};  

var test2 = function (){
    return function(){
        alert("foo");
    };
};

var test3 = function (k){
    return k();
};

test1(); // hoge

var a = test2();
a(); // foo

test2()() // foo

test3(test2)(); // foo
var b = test2();
test3(b); // foo

thisは呼び出された変数を保持しているオブジェクトで変化します

thisの参照は呼び出された関数を保持しているモノによって変化します。

var say = function (){
    alert(this.message);
};

var hoge = {
    message: 'hoge'
};  

var foo = {
    message: 'foo'
};  

hoge.say = say;
foo.say = say;

hoge.say(); // hoge
foo.say(); // foo

これを分かりやすくapplyとかcallとかって別名で呼ぶ事もあります。

var say = function (){
    alert(this.message);
};

var hoge = {
    message: 'hoge'
};  

var foo = {
    message: 'foo'
};  

say.apply(hoge, null); // hoge
say.call(foo, null); // foo

でも、applyやcallは委譲を行うためにも使えます

applythisの参照先を変更できるので、委譲するときにも使います。

var Main = {
    hello: function (){
        alert(this.world());
    }
};  

var hoge = {
    world: function (){
        return 'hoge world';
    }
};  

var foo = {
    world: function (){
        return 'foo world';
    }
};  

var hello = Main.hello;
hello.apply(hoge, null); // hoge world
hello.apply(foo, null); // foo world

参照とはなんでしょうか?それは変数を触れる事ができる範囲の定義です

変数で宣言したものには、参照先が決まっています。その参照の範囲はスコープとも呼びます。

var a = 1;
var hoge = function (lambda){
    alert(a); // undefined;
    lambda(); // 1
    var a = 2;
    lambda(); // 1
    alert(a); // 2;
};  

var foo = function (){
    alert(a);
};  

hoge(foo);
alert(a); // 1;

引数の変数にも参照はあります。

var hoge = function(arg0, arg1){
    return function (k){
        alert(arg0 + arg1); // 'helloworld'
        k();
    };  
};  

var foo = hoge('hello', 'world');
foo(function (){
    alert(typeof arg0); // undefined
    alert(typeof arg1); // undefined
});

参照できる値そのものを渡すことも可能です。

var hoge = function(arg0, arg1){
    return function (k){
        return function (){
            return k(arg0, arg1);
        }
    };
};  

var foo = hoge('hello', 'world');
var bar = foo(function (arg0, arg1){
    alert(arg0 + arg1); // 'helloworld'
}); 
bar();

こうした動きはクロージャやレキシカルスコープという呼び名があり、うまく使うと便利です

var createCounter = function (){
    var count = 0;
    return function (){
        return count++;
    };  
};  

var counter = createCounter();
alert(counter()); // 0
alert(counter()); // 1
alert(counter()); // 2
alert(counter()); // 3

メソッドとは何でしょうか?それは関数の参照を持っているだけのモノです。

メソッドの呼び出しは参照の違いでしかないです。

var message = 'this is global';
var Hoge = function (){
    var message = 'this is hoge';
    this.say = function (){
        return message; 
    }   
};  

var hoge = new Hoge;
alert(hoge.say()); // this is hoge

var Foo = function (){};
var foo = new Foo; 
foo.say = hoge.say;
alert(foo.say()); // this is hoge

var Bar = function (){
    this.say = function (){
        return message;
    }
};  

var bar = new Bar;
alert(bar.say()); // this is global

コンストラクタとは何でしょうか?それはthisの参照を明示的に指定しているだけの関数です。

thisで呼び出すには、オブジェクトにしないといけないです。いわゆるインスタンス化です。それはコンストラクタを通して行われます。
ref - ハタさんのブログ : javascriptのコンストラクタとか

var Hoge = function (msg){
    this.message = msg + ' is Hoge';
    return this.message;
};  

var hoge1 = Hoge('hello');
alert(hoge1); // hello is Hoge
alert(hoge1.message); // undefined

var hoge2 = new Hoge('world');
alert(hoge2); // [object Object]
alert(hoge2.message); // world is Hoge

var Foo = function(msg){
    this.toString = function (){
        return msg + ' is Foo';
    }
    return msg;
};  

var foo1 = Foo('abc');
alert(foo1); // abc
alert(foo1.toString()); // abc

var foo2 = new Foo('def');
alert(foo2); // def is Foo
alert(foo2.toString()); // def is Foo

次のString関数はコンストラクタの呼び出しと関数の呼び出しがあります。

var message1 = String('message one');
var message2 = new String('message two');

alert(message1); // message one
alert(message2); // message two
alert(typeof message1); // string
alert(typeof message2); // object

おさらい。その1

ということで、その1のおさらいとしては、関数と変数と参照になります。
thisは単なるスコープで、参照はthisが持っていますし、変数の参照先によって違う値を持てます。
また、変数は値もしくは式の別名で、それもまた参照を持てるということがわかりました(?)

というか、↓に書かれている事が関数型言語について全てを物語っているのですが、やはり少しづつ学んで貰うのがベストかと。
via - 関数型言語(プログラミング言語Scheme, Haskellなど)を勉強しようと思っています。 初心者にも関数型言語のメリットや考えかたがスラスラ分かる勉強の材料を教えてくださ.. - 人力検索はてな

ECMAScript 特有のプロトタイプや可変引数、クロージャについてもっとkwskや高階関数、applyとかsetTimeout、イベント系、 DOM系については順を追って、その2、その3へ。

つづく


Trackback

No Trackbacks

Track from Your Website

http://blog.xole.net/trackback/tb.php?id=640

5 Comments

Re: javascriptを初めて学ぶ人についてのおさらい。その1

ものすごーく分かりやすいです!!

From : くみこ @ 2007-12-01 06:40:16 編集

Re: javascriptを初めて学ぶ人についてのおさらい。その1

すごく分かりやすいです!
ただ…

var hoge = function (lambda){
alert(a); // undefined;
lambda(); // 1
var a = 2;
lambda(); // 1
alert(a); // 2;
};

この『lambda(); // 1』ってところが分かりません…(T_T)
何故1が返るんでしょうか?

From : hoge @ 2007-12-01 11:06:28 編集

Re: javascriptを初めて学ぶ人についてのおさらい。その1

>くみこさん

ありがとうございます。励みになります!

>hogeさん

それは、以下のようにすれば分かりますでしょうか?
lambda()ではhogeのスコープではなく、その外側のスコープについて変数aの評価をしていると言えます。

var a = 1;
var hoge = function (){
alert(a); // undefined;
var a = 2;
alert(a); // 2;
};

var foo = function (){
alert(a); // 1
};

hoge();
foo();

また、hoge()内で、aがundefinedになってしまうのは、hoge内で、既に宣言済み変数aについて定義し直したためといえます。
関数hogeは次のようにも書き換える事ができます。

var a = 1;
var hoge = function (){
var a;
alert(a); // undefined;
a = 2;
alert(a); // 2;
};

hoge();

ということで、関数内にあるスコープと、その外側で宣言されたスコープは別の場所に参照されるということになります。

From : ハタ @ 2007-12-01 23:17:09 編集

Re: javascriptを初めて学ぶ人についてのおさらい。その1

hogeさん同様にlambda()がわからなかったけど、それも理解できました。
まじわっかりやすいです!その2が超楽しみです、応援してます!

From : q @ 2007-12-02 03:33:10 編集

理解できました♪

スコープ以前に引数lambdaの意味が分かっていませんでした。
この場合はlamda = fooなんですね。(要するにlamda() = foo())

引数(変数?)に関数が代入できるっていうのが、
感覚的にしか理解できてませんでした…

> aがundefinedになってしまうのは、hoge内で、既に宣言済み変数aについて定義し直したためといえます。
あと、これは驚きました。
自分だけかも知れませんがJavascriptってスコープ領域がかなり分かり辛いです…

でも今回のエントリでJavascriptが随分読めるようになりました♪

ありがとうございました。

From : hoge @ 2007-12-02 12:54:16 編集

Post Your Comment


*は入力必須です。E-Mailは公開されません。

1 + 2 =