LoginSignup
6
6

More than 5 years have passed since last update.

JavaScript 継承のようなもの

Last updated at Posted at 2016-04-07

最初に

pythonやrubyといった他の言語は割とわかりやすいですが、JSはprototypeがベースだから結構 異なる気がする。
たぶんJavaScriptにおける継承のパターン4種類の概要と対比とか参考にされていると思いますが、スコープ(っぽいもの)がわかりづらくあまり好みの書き方ではありません。 自分の好みの書き方で継承っぽいものをしてみます。
※ECMAScript 5です。 6からはclass,extendsを使って下さい。(class実装するの遅くない?)

結論

とりあえず、最初に結論を…

var F1 = function(){
  this.a = "a"
  F1.prototype.print = function(){
    console.log(this.a);
  }
}
var F2 = function(){
  this.b = "b";
  F2.prototype.printa = function(){
    console.log(this.a);
  }
  F2.prototype.printb = function(){
    console.log(this.b);
  }
}
F2.prototype = new F1();//スコープ(っぽい)物の外で行う。(重要)

//main
var f2 = new F2();
f2.printa() // => "a"
f2.printb() // => "b"
f2.print() // "a"

F2.prototype = new F1 関数と変数両方を自分のprototypeへ追加できます。

検証みたいなの

環境

chrome 49.0.2623.110 m
firefox 45.0.1 + firebug

パターン1 初っ端に追加

var F1 = function(){
  this.a = "a"
  F1.prototype.print = function(){
    console.log(this.a);
  }
}
var F2 = function(){
  F2.prototype = new F1();//スコープ(っぽい)物の中で行う。
  this.b = "b";
  console.log(this.a) // => undefined
  F2.prototype.printa = function(){
    console.log(this.a);
  }
  F2.prototype.printb = function(){
    console.log(this.b);
  }
}

//main
var f2 = new F2();
f2.printa() // Uncaught TypeError: f2.printa is not a function
f2.printb() // 同じく
f2.print() // 同じく

ダメ。

f2 {b: "b"}
    _proto_:Object
    constructor:F2()
    _proto_:Object

勿論、プロパティにF1のプロパティはない。

パターン2 少し後に追加

var F1 = function(){
  this.a = "a"
  F1.prototype.print = function(){
    console.log(this.a);
  }
}
var F2 = function(){
  this.b = "b";
  console.log(this.a) // => undefined
  F2.prototype = new F1();
  F2.prototype.printa = function(){
    console.log(this.a);
  }
  F2.prototype.printb = function(){
    console.log(this.b);
  }
}

//main
var f2 = new F2();
f2.printa() // Uncaught TypeError: f2.printa is not a function
f2.printb() // 同上
f2.print() // 同上

パターン1と同じく ダメ。
f2のプロパティも同じ。

パターン3 2つの関数の間

var F1 = function(){
  this.a = "a"
  F1.prototype.print = function(){
    console.log(this.a);
  }
}
var F2 = function(){
  this.b = "b";
  console.log(this.a) // => undefined
  F2.prototype.printa = function(){
    console.log(this.a);
  }
  F2.prototype = new F1();
  F2.prototype.printb = function(){
    console.log(this.b);
  }
}

//main
var f2 = new F2();
f2.prototype // undefined
f2.printb() // Uncaught TypeError: f2.printb is not a function
f2.print() // 同上

f2プロパティへprintaは登録されてるみたい。
f2を覗いてみる

f2 {b: "b"}
    b:"b"
    __proto__:Object
    constructor:function()
    printa:function()
        arguments:null
        caller:null
        length:0
        name:""
    prototype:Object
    __proto__:function()
    <function scope>
    __proto__:Object

F1はない。

パターン4 一番最後

var F1 = function(){
  this.a = "a"
  F1.prototype.print = function(){
    console.log(this.a);
  }
}
var F2 = function(){
  this.b = "b";
  console.log(this.a) // => undefined
  F2.prototype.printa = function(){
    console.log(this.a);
  }
  F2.prototype.printb = function(){
    console.log(this.b);
  }
  F2.prototype = new F1();//最後
}

//main
var f2 = new F2();
f2.printa() // undefined
f2.printb() // b
f2.print() // Uncaught TypeError: f2.print is not a function

printbは動いた。
prototypeにF1はないから printaのaはundefinedとなっている。
f2のプロパティを見る。

F2 {b: "b"}
b:"b"
__proto__:Object
constructor:function()
printa:function()
    arguments:null
    caller:null
    length:0
    name:""
    prototype:Object
    __proto__:function()
    <function scope>
printb:function()
    arguments:null
    caller:null
    length:0
    name:""
    prototype:Object
    __proto__:function()
<function scope>
__proto__:Object

やはりF1はない。

パターン5 スコープ外へ

結論にあるコードのf2プロパティ

F2 {b: "b"}b: "b"
    __proto__: F1
    a:"a"
    printa:function()
        //中はパターン4と同じ
    printb:function()
        //中はパターン4と同じ
    __proto__:Object

ちゃんとF1が追加されている。

検証まとめ

パターン1~4はF2の関数を定義している間にそのprototypeに違う関数のprototypeを入れようとするが、そもそも入れるための器が無かった。
(newした時の__proto__はnewされる関数のprototypeを参照します。ソースはMDN)
F2自体を定義するために、スコープの外でprototypeに追加する必要がある。(当たり前と言えば当たり前)

 最後に

ECMAScript 6を使うと幸せになる。(はず)
しかし、prototypeからは逃れられない。

書き方とかもっと良いものがあれば是非コメント下さい。

6
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6