【挫折ポイント解説】JavaScriptのクラス、オブジェクトについて③
こんにちは!りんごです
前回の記事では、クラスの一番最初の作り方に関して解説しました。
まだ1回目の記事を呼んでいない方はコチラ
前回までだと、確かこんな感じ終わりましたね。
// フルーツクラス
class Fruit{
}
let apple = new Fruit()
console.log(apple)
では話を進めましょう!
先ほど作っていただいたフルーツですが、
本当にそれはリンゴですか?
今のところ変数名にappleと名付けただけで、
そんなのは中身がリンゴであると言う根拠には到底なり得ません。
そこで、リンゴである証拠を遺伝子情報として組み込む必要があります。
// フルーツクラス
class Fruit{
constructor() {
this.name = "リンゴ"
this.color = "赤"
this.taste = "甘酸っぱい"
}
}
let apple = new Fruit()
console.log(apple)
開発者ツールで確認すると、このように表示されました。
ここで新しく出てきたconstructor()と言う関数ですが、
これは組み込み関数と言ってJSが元々用意している関数の1つです。
組み込み関数は他にも、
皆さんお馴染みのconsole.log()とかalert()とか色々ありますよね。
※上記は正しくはブラウザAPIが用意する組み込み関数ですが、今は難しく考えなくて大丈夫です。
とにかく、この関数自体に身構える必要は何もなくて
newした時に一度だけ呼ばれる唯一の関数とだけ思っていてください。
どちらかと言うと、問題はその中に書かれている内容の方でしょう。
突然、this.○○と書かれていますがこのthisとは何者でしょうか?
// フルーツクラス
class Fruit{
constructor() {
this.name = "リンゴ"
this.color = "赤"
this.taste = "甘酸っぱい"
}
}
thisとは自分が属しているオブジェクトのことを指しており、記述する場所によって対象が変わってしまう魔法の変数です。
…………………。
…………つまり
…どう言うことだってばよ?
例えば下記のように書いてみた場合はどうでしょうか?
// フルーツクラス
class Fruit{
constructor() {
this.name = "リンゴ"
this.color = "赤"
this.taste = "甘酸っぱい"
console.log(this) // ①
}
}
let apple = new Fruit()
console.log(this) // ②
console.log(this)を2箇所に仕込んでみました。
1つはconstructor内に、もう一つは何もないところです。
結果はこうなります。
Fruitの中におけるthisとは、
Fruitから生成されたオブジェクト自身のことを指します。
そして何もないところで書いたthisは、
Windowクラスから生成されたオブジェクト自身のことを指しており、これは何も書かなくてもあらかじめ利用できるオブジェクトです。
windowオブジェクトに関してはそれだけで記事が1つ出来てしまいそうなので、今は深く触れません。
重要なのは、thisが帰属する対象はより直近のオブジェクトに移ると言う習性です。これが数多くの学習者を悩ませている元凶と言っても良いかもしれませんね。
↓ thisのイメージ
ただし今回の例では他の対象に移ることはないので、安心してクラスとオブジェクト自体の理解に集中してください。
↓ 今回のthisのイメージ
ではコードの解説に戻ります。こんな感じでしたね。
// フルーツクラス
class Fruit{
constructor() {
this.name = "リンゴ"
this.color = "赤"
this.taste = "甘酸っぱい"
}
}
let apple = new Fruit()
JavaScriptにおいて、class直下に書くことが出来るのは基本的に関数かプロパティのみです。
いきなり処理を書いたり、変数を置いたりするのはダメです。
// フルーツクラス
class Fruit{
let name = "リンゴ" // これはNG
console.log("吾輩はリンゴである") // これもNG
name() {
console.log("吾輩はリンゴである") // これはOK
}
}
ただし下記のように直接プロパティを置く書き方は、2020年3月28日現在、あくまで実験的に出来るようになっているため、ここではあまり触れないこととします。
// フルーツクラス
class Fruit{
name = "リンゴ" // ブラウザによっては動かないらしい
}
話を戻して、constructor()も関数の1つなので問題ないでしょう。
// フルーツクラス
class Fruit{
constructor() {
this.name = "リンゴ"
this.color = "赤"
this.taste = "甘酸っぱい"
}
}
let apple = new Fruit()
では中に書かれているthis.name = "リンゴ"が何かと言うと、this.nameがプロパティで、"リンゴ"が値になります。
生成されるオブジェクトに対してステータスを設定しているような感じですね。
もしこれにより生成されるオブジェクトの色を知りたければ、
生成された実態であるappleさんに聞いてみてください。
// フルーツクラス
class Fruit{
constructor() {
this.name = "リンゴ"
this.color = "赤"
this.taste = "甘酸っぱい"
}
}
let apple = new Fruit()
console.log(apple.color)
ちなみに生成される前の、レシピの段階から色を知る方法もあります。
class Fruit{
constructor() {
this.name = "リンゴ"
this.color = "赤"
this.taste = "甘酸っぱい"
}
static Color = "赤"
static GetColor() {
return "赤"
}
}
console.log(Fruit.Color)
console.log(Fruit.GetColor())
staticをプロパティあるいは関数の前に置くことで、
このようにnew Fruit()することなく利用することができます。
ただし反対に、
生成された実態からstaticなプロパティ・メソッドにアクセスすることは出来ないので注意が必要です。
class Fruit{
constructor() {
this.name = "リンゴ"
this.color = "赤"
this.taste = "甘酸っぱい"
}
static Color = "赤"
static GetColor() {
return "赤"
}
}
let apple = new Fruit()
console.log(apple.Color)
console.log(apple.GetColor())
…3000字を超えてしまったため一旦ここで区切ります。
次回はここで設計したリンゴさんを使って、クローンリンゴを作るところから説明していきたいと思います!
ではでは!ここまでの疑問などありましたらコメント欄にお願いします。
フォローなどもお待ちしております!