Javascriptを勉強し始めた者です。
オブジェクトと変数の関係の概念がいまいち理解できなかったので、以下のコードをもとに質問させてください。
javascript
1var person = function(){ 2 this.name = "no name"; 3} 4 5var me = new person(); 6
■質問1
1行目で宣言した変数personの型はオブジェクトですか?
■質問2
1行目で宣言したpersonがオブジェクトだとすると、下部で new person(); とオブジェクトを生成する意味は何でしょうか?
オブジェクトではない場合、person の型は何でしょうか?
よろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
ベストアンサー
Object 型
コンストラクタ(new
演算子で呼べる関数)の関数名は先頭を大文字にする慣習がある為、名前を変えます。
JavaScript
1var Person = function(){ 2 this.name = "no name"; 3} 4 5var me = new Person();
変数 Person
, me
はどちらも「Object 型」です。
一部には new Function
を「Function型」、new Person
を「Person型」と呼ぶ場合もありますが、それらと「JavaScriptとしての型」は別物なので、厳密な意味では間違った表現(便宜上の説明)です。
性質 | Person | me |
---|---|---|
型 | Object型 | Object型 |
[[Call]] を持っているか | 持っている(関数である) | 持っていない(関数ではない) |
インスタンス生成元 | Function | Person |
[[Prototype]] (__proto__ ) | Function.prototype | Person.prototype |
インスタンス生成元としての「型」を「Person型」と呼ぶ場合があるわけですが、プロトタイプチェーンを辿れば、多くの型を持っている扱いとなります。
JavaScript
1var Person = function(){ 2 this.name = "no name"; 3} 4 5var me = new Person(); 6 7console.log(Person instanceof Function); // true (Function型) 8console.log(Person instanceof Object); // true (Object型) 9console.log(me instanceof Person); // true (Person型) 10console.log(me instanceof Object); // true (Object型)
この表現方法は厳密な意味では「JavaScriptの型」とは違いますし、多くの型を併せ持つ性質は理解されづらいなので、個人的には混乱を招く可能性の高い表現だと思っています。
結論としては、両方ともObject型です。
プロトタイプ
JavaScriptはプロトタイプベースの言語です。
Person.prototype
はオブジェクトの雛形(プロトタイプ)であり、new Person
という命令によって、Person.prototype を雛形(プロトタイプ)とするオブジェクトを生成します。
そうすることによって、Person
の性質を持つオブジェクトを複数生成できます。
プロトタイプチェーン
JavaScriptではプロパティ参照の際には必ず、プロトタイプチェーンを辿る事でプロパティを検索します。
(new
演算子とセットで説明されることが多いですが、これは new
演算子を使った場合限定の規則ではありません)
JavaScript
1'use strict'; 2function Person (name) { 3 this.name = arguments.length ? name : 'no name'; 4} 5 6Person.prototype.output = function output () { 7 console.log(this.name); 8}; 9 10var taro = new Person('taro'); 11 12taro.output(); // "taro" (new Person は Person.prototype に存在するプロパティを使用できる) 13 14console.log(taro.output === Person.prototype.output); // true (taroのプロパティを参照する時、暗黙の内に Person.prototype に存在するプロパティを検索する) 15console.log(Object.getPrototypeOf(taro) === Person.prototype); // true (new Person の [[Prototype]] は Person.prototype である) 16console.log(taro.__proto__ === Person.prototype); // true (同上)
注目してほしいのは、taro.output === Person.prototype.output
が true
となる部分です。
taro.output
が参照された場合、taro
は直属のプロパティとして output
を持っていない為、prototypeである Person.prototype
から output
プロパティを探し、見つかった為、それを参照しているわけです。
ここでもし、Person.prototype.output
が存在しなかったのなら、更に上の prototype を探し、prototype が存在しなくなるまでこの過程を繰り返します。
この仕組みをプロトタイプチェーンといいます。
Re: dada_moreo さん
投稿2017/09/05 01:03
編集2017/09/05 10:20総合スコア18162
0
1行目で宣言した変数personの型はオブジェクトですか?
いいえ、これは関数です※
ただし、new
を使ってインスタンスを作ることを想定した関数です。
new
が何やってんねんってのいうのがわかれば自ずと理解出来ます。
newを使って関数を叩くと、まず空のオブジェクトを作ります。
関数内部でthis.hoge = 123;
という風にthis
に向かってプロパティを詰めていくと、
newで作られた空のオブジェクトのプロパティに値が詰め込まれていきます。
そして、ここが重要!
newを使って関数が実行されると、最初に作ったオブジェクトだったものが戻り値として帰ってきます。
関数内のreturn
じゃないよ!
要するに変数me
はnew person()
と指定するから、必ずオブジェクトが代入されるってわけ。
なので、thisのプロパティに値を突っ込む事が目的の変な関数が出てきたら、
それは他の言語で言うクラスに相当する雛形的な関数と解釈してください。
ちょっとだけ変な書き方になりますが、クラスベースのオブジェクト指向言語と同じ事は可能です。
(ES2015ではClass構文がサポートされ、他の言語のようなクラス宣言が出来るようになりました)
Bash
1var person = function() { 2 this.name = "hogehoge"; 3} 4 5var me = new person(); 6 7console.log(me); 8// person {name: "hogehoge"}
newを使って作られたオブジェクトはただのオブジェクトではなく、
関数であるperson
のインスタンスとして動作するオブジェクトになります。
console.log
で中身を表示するとちゃんとperson
のインスタンスって表示されることが確認出来ます。
ついでに定義しておいたpersonのメソッド(プロトタイプのプロパティ)にアクセスできます。
JavaScript
1var person = function() { 2 this.name = "hogehoge"; 3} 4// これがメソッド定義 5person.prototype.hello = function() { 6 return "hello. my name is " + this.name; 7} 8 9var me = new person(); 10 11console.log(me); 12// person {name: "hogehoge"} 13 14console.log(me.hello()); 15// "hello. my name is hogehoge"
1行目で宣言したpersonがオブジェクトだとすると、下部で new person(); とオブジェクトを生成する意味は何でしょうか?
オブジェクトではない場合、person の型は何でしょうか?
JavaScriptはプロトタイプベースのオブジェクト指向言語という話を聞いたことありませんか?
(その気になれば)全ての関数をnewして新しいインスタンスを生成することが可能です。
現実的にはthisに値を突っ込むコンストラクタメソッド的な関数しかプロトタイプの元には成りえないので、
雛形に相当する関数を予め作っておく(プロトタイプ)、それを元に新しいインスタンスを生成する(new)
正にコピーを作りながら量産するという考え方になります。
継承の代わりになるのがプロトタイプのコピー及び改良。
ちょっとしたコードを買いて見せたかったけど、ちゃんとした書き方は大変なので参考サイト張っておきます。
参考サイト:継承とプロトタイプチェーン - MDN
※Rubyは完全なオブジェクト指向言語なので数値や文字列も全てオブジェクトですが、
JavaScriptも不完全ながら似たようなアプローチで、Number, String, Boolean
等のプリミティブなもの以外はオブジェクトから派生して作られたものです。
JavaScriptの関数はFunctionというオブジェクトを使って生成されたものです。
「変数personの型はオブジェクトですか?」という問いに関しては、
その通りと回答するのが正解なのですが、
今回の質問に限ってはそういう分類に対する質問とは異なると考え、否定しています。
投稿2017/09/05 01:21
編集2017/09/05 01:57総合スコア21158
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/05 07:57
2017/09/05 08:21
0
質問1 1行目で宣言した変数personの型はオブジェクトですか?
「function
オブジェクト」です。JavaScriptでは、関数もオブジェクトなのです。
質問2
person
という関数を使って、新たなオブジェクトを作る操作、です。
投稿2017/09/04 22:26
総合スコア145183
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
person
はオブジェクトであり、その型は「関数オブジェクト」です。
me
はオブジェクトであり、型は無名ですが、person
で示される型です。
変数 (や定数) には、オブジェクトとプリミティブがあります。プリミティブはそれ以上の構造を持たない数 (12
とか 1.5
とか) や文字列 ("test" とか) などがあります。それ以外はオブジェクトと考えてさしつかえないと思います。
new person()
でオブジェクトを生成するメリットは、person
型の prototype にメソッド (たとえば、walk()
) を追加すると、そのメソッドの実体が一つでも、生成したオブジェクト、たとえば me
から me.walk()
のように me
自体のメソッドのように呼べること、などです。
コメントを受けて追記
person
はfunction
という型のインスタンスです。me
はperson
という型のインスタンスです。
もうちょっと詳しく書くと、
person
はfunction
という型のインスタンスです。関数オブジェクトとも言います。関数オブジェクトは型となれます。me
はperson
という変数に格納された関数オブジェクトを型としたときのインスタンスです。
という感じです。
例を示しながら。
js
1var person = function() { 2 this.name = "no name"; 3} 4 5var me = new person(); 6var he = new person(); 7var it = new person(); 8 9person.prototype.setName = function(name) { 10 this.name = name; 11 return this; 12}; 13 14person.prototype.isHuman = true; 15 16person.prototype.greet = function() { 17 console.log("my name is " + this.name + " (" + (this.isHuman ? "human" : "?")\ 18 + ")."); 19}; 20 21me.bark = function() { 22 console.log(this.name + "!!!"); 23}; 24 25it.isHuman = false; 26 27me.setName("Taro").greet(); //-> my name is Taro (human). 28he.setName("Jiro").greet(); //-> my name is Jiro (human). 29it.greet(); //-> my name is no name (?). 30me.bark(); //-> Taro!!! 31he.bark(); //-> エラー発生 (he.bark is not a function)
person
型のオブジェクト me
, he
, it
を生成しました。me
にはオブジェクト固有のメソッド bark()
が定義してあります。it
には固有のプロパティ isHuman
が定義してあります。これらは、オブジェクトごとに記憶領域を持っているわけです。
一方で、setName()
メソッドや greet()
メソッド、そして isHuman
プロパティについては、person
という型のほうに定義してあります。これらは person
型の記憶領域に保存されているので、person
型のインスタンスをいくら生成しても、これらの分の記憶領域は消費されません。
投稿2017/09/04 22:25
編集2017/09/04 23:53総合スコア2468
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/04 22:57
2017/09/04 23:54
2017/09/05 01:13
2017/09/05 01:16
2017/09/05 03:52
2017/09/05 08:00
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/05 02:30
2017/09/05 03:07
2017/09/05 07:58
2017/09/05 08:19
2017/09/05 08:23
2017/09/05 09:33
2017/09/05 10:24
2017/09/05 12:47
2017/09/05 13:18
2017/09/06 11:47