Learning JavaScript

曖昧な知識をきちんと自分のものにしたい。

がわかりやすかった。

プロトタイプチェーン

var a = {name: 'a'};
var b = Object.create(a);

console.log(b.__proto__ === a); // true
console.log(b.name);  // a
var c = {name: 'c'};
c.prototype = { say: function(){ alert(this.name); } };

var d = Object.create(c);

console.log(d.__proto__ === c); // true
console.log(d.say); // undefined

__proto__はプロトタイプチェーンの探索に使われる。 dのプロトタイプはcであって、c.prototypeではないので、d.say はundefined になる。

コンストラクタ関数とnew

function Dog(name) {
  this.name = name;
}
Dog.prototype = {bark: 'wooo!'};

var pochi = new Dog('pochi');


// pochi has own property 'name'
console.log(pochi.name);
console.log(pochi.hasOwnProperty('name'));

// __proto__ equals to constractor's prototype
console.log(pochi.__proto__ === Dog.prototype);

// pochi does not have prototype
console.log(pochi.hasOwnProperty('prototype'));

// pochi can bark
console.log(pochi.bark);

// pochi.prototype is undefined
console.log(pochi.prototype);

prototypeはnewでオブジェクト生成した際に、継承先の__proto__に代入されるという理解でよさそう。

スコープ

var variable = 'global';

function logger() {
    var variable = 'local';
    console.log(variable); 
}

function logger2() {
    variable = 'local';
    console.log(variable);
}

console.log(variable); // global
logger(); // local
logger2(); // local
console.log(variable); // local !!!

変数を新しく割り当てる時は、varで宣言する必要あり。 関数の{}がローカルスコープとなる。

this

function Dog(name) {
    this.name = name;
    this.say  = function() { alert(this.name); };
}

var pochi = new Dog('pochi');
var tama  = { name: 'tama' };

tama.say = pochi.say;
tama.say(); // tama
pochi.say(); // pochi

関数はオブジェクトに束縛されず、thisは実行時に関数が属するオブジェクトを参照する。

call/apply

    function say(greeting, period) {
        console.log(greeting + ', ' + this.name + period);
    }

    var person = {
        name: 'kotaroito'
    };

    say.call(person, 'Hi', '.');
    say.apply(person, ['Hello', '!']);

call/applyは束縛するthisオブジェクトを指定することができる。callとapplyの違いは第二引数以降で、callは引数を並べ、applyはArrayオブジェクトを渡す。

bind

function say(arg) {
    var str = 'My name is ' + this.name + '. I am a ' + arg + '.';
    alert(str);
}

var pochi = { name: 'pochi' };

(say.bind(pochi))('dog');

bindは引数オブジェクトをthisに束縛した新しい関数をつくる。

まとめ

  • ¥protoを辿ることでプロトタイプチェーンが実現される
  • prototypeに設定されたオブジェクトはnew演算子によって、継承先オブジェクトのプロトタイプチェーンに入る
  • 関数ブロックがローカルスコープとなり、解決できなければ1つ上のスコープを見る
  • 関数はオブジェクトに束縛されずに、thisは実行時に関数が属するオブジェクトを参照する
  • call/applyでthisが指すオブジェクトを指定できる
  • bindは与えられた引数でをthisに束縛した関数を返す