JavaScript 入門

Hitoshi Amano

プログラミングのこつ

無駄な名前を極力使わないこと。意味単位に名前空間を細かく階層的に分離すること。

ここで言う名前空間とは

名前空間とは、一つの名前が一意のものを表す空間。例えば、大きな目で見れば、日本語は自然言語の名前空間である。また、専門用語なども名前空間と考えることが出来る。

日本語 {
    コンニチワ = 挨拶
    :
    :
}
中国語 {
    ニーハオ = 挨拶
}
英語 {
    ハロー = 挨拶
}

また、名前空間は重なり(優先順位)を持つ

同音異義語などの言葉は、それぞれの細かい名前空間の重なりによって一意のものに特定されると考えられる

たとえば、「コイが好き」と言った場合

池に関する名前空間           { コイ = すいすいパクパク }
チャライ話題に関する名前空間 { コイ = ドキドキきゅんきゅん }
お茶に関する名前空間         { コイ = にがーい }

名前空間の優先順位を考えると、一意の意味を知ることができる。

JavaScript 入門

構造化されていない場合

var element = document.getElementById('target001');
var left = 0; 
var id = setInterval(moveBox, 20);
function moveBox() {
    left += 4;
    element.style.left = left + 'px';
    if (left == 400) clearInterval(id);
}

exec

グローバル名前空間に 4 つの名前 element, id, left, moveBox が生成される

構造化された場合

var box = {
    element: document.getElementById('target002'),
    left: 0,
    id: setInterval(moveBox, 10)
};
function moveBox() {
    box.left += 4;
    box.element.style.left = box.left + 'px';
    if (box.left > 400) clearInterval(box.id);
}

exec

グローバル名前空間の汚染は 2 つに減る。

オブジェクトを使う場合

var box = {
    element: document.getElementById('target003'),
    left: 0,
    move: function() {
        box.left += 4;
        box.element.style.left = box.left + 'px';
        if (box.left > 400) clearInterval(box.id);
    },
    start: function() {
        this.id = setInterval(this.move, 20);
    }
};
box.start();

exec

一つの名前に集約できたしかし、名前 box を使いまわせない

名前 box を使いまわせなるように、 this を使う

var box = {
    element: document.getElementById('target004'),
    left: 0,
    move: function() {
        this.left += 4;
        this.element.style.left = this.left + 'px';
        if (this.left > 400) clearInterval(this.id);
    },
    start: function() {
        var self = this;
        this.id = setInterval(function() { self.move() }, 20);
    }
};
box.start();

exec

じゃあ、二つ以上の box だったらどうよ

function createBox(id) {
    return {
        element: document.getElementById(id),
        left: 0,
        move: function() {
            this.left += 4;
            this.element.style.left = this.left + 'px';
            if (this.left > 400) clearInterval(this.id);
        },
        start: function() {
            var self = this;
            this.id = setInterval(function() { self.move() }, 20);
        }
    };
}

var box1 = createBox('target005-1');
var box2 = createBox('target005-2');

box1.start();
box2.start();

exec

box1, box2 の共通の値を定義する

var boxSpeed = 4;
function createBox(id) {
    return {
        element: document.getElementById(id),
        left: 0,
        move: function() {
            this.left += boxSpeed;
            this.element.style.left = this.left + 'px';
            if (this.left > 400) clearInterval(this.id);
        },
        start: function() {
            var self = this;
            this.id = setInterval(function() { self.move() }, 20);
        }
    };
}

var box1 = createBox('target006-1');
var box2 = createBox('target006-2');

box1.start();
box2.start();

setTimeout(function() { boxSpeed = 1 }, 600);

exec

グローバル変数がモッタイナス><、プロトタイプを使う

function Box(id) {
    this.element = document.getElementById(id);
    this.left = 0;
    this.move = function() {
        this.left += this.speed;
        this.element.style.left = this.left + 'px';
        if (this.left > 400) clearInterval(this.id);
    };
    this.start = function() {
        var self = this;
        this.id = setInterval(function() { self.move() }, 20);
    };
}
Box.prototype.speed = 4;

var box1 = new Box('target007-1');
var box2 = new Box('target007-2');

box1.start();
box2.start();

setTimeout(function() { Box.prototype.speed = 1 }, 600);

exec

てか、関数も共通だよね!

function Box(id) {
    this.element = document.getElementById(id);
    this.left = 0;
}
Box.prototype.speed = 4;
Box.prototype.move = function() {
    this.left += this.speed;
    this.element.style.left = this.left + 'px';
    if (this.left > 400) clearInterval(this.id);
};
Box.prototype.start = function() {
    var self = this;
    this.id = setInterval(function() { self.move() }, 20);
};

var box1 = new Box('target008-1');
var box2 = new Box('target008-2');

box1.start();
box2.start();

setTimeout(function() { Box.prototype.speed = 1 }, 600);

exec

みにくいのでオブジェクトを入れ替える方式に

function Box(id) {
    this.element = document.getElementById(id);
    this.left = 0;
}
Box.prototype = {
    speed: 4,
    move: function() {
        this.left += this.speed;
        this.element.style.left = this.left + 'px';
        if (this.left > 400) clearInterval(this.id);
    },
    start: function() {
        var self = this;
        this.id = setInterval(function() { self.move() }, 20);
    }
};

var box1 = new Box('target009-1');
var box2 = new Box('target009-2');

box1.start();
box2.start();

setTimeout(function() { Box.prototype.speed = 1 }, 600);

exec

複数要素

function Box(e) {
    this.element = e;
    this.left = 0;
}
Box.prototype = {
    speed: 4,
    move: function() {
        this.left += this.speed;
        this.element.style.left = this.left + 'px';
        if (this.left > 400) clearInterval(this.id);
    },
    start: function() {
        var self = this;
        this.id = setInterval(function() { self.move() }, 20);
    }
};
var nl = document.getElementById('target010').getElementsByTagName('div');
for (var i = 0, l = nl.length; i < l; i ++) {
    var e = nl[i];
    with({e:e})
    setTimeout(function() {
        var box = new Box(e);
        box.start();
    }, i * 500);
}

exec

使い捨て変数名前空間

function Box(e) {
    this.element = e;
    this.left = 0;
}
Box.prototype = {
    speed: 4,
    move: function() {
        this.left += this.speed;
        this.element.style.left = this.left + 'px';
        if (this.left > 400) clearInterval(this.id);
    },
    start: function() {
        var self = this;
        this.id = setInterval(function() { self.move() }, 20);
    }
};

(function() {
    var nl = document.getElementById('target011').getElementsByTagName('div');
    for (var i = 0, l = nl.length; i < l; i ++) {
        var e = nl[i];
        with({e:e})
        setTimeout(function() {
            var box = new Box(e);
            box.start();
        }, i * 500);
    }
})();

exec

DOM(時間があまったら)

まあ、なんだかんだいっても JavaScript は DOM を暗記すればスラスラ書ける

天気という文字列を抽出せよ

<p id="target012">今日はいい<strong>天気</strong>だ。</p>

今日はいい天気だ。

答えの例はここを click!!

exec

strong をすべて em にせよ

<p id="target013"><strong>今日</strong>はいい<strong>天気</strong>だ。</p>

今日はいい天気だ。

答えの例はここを click!!

exec