質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

1114閲覧

コンストラクタがわかりません。

kantowebmanager

総合スコア29

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

2クリップ

投稿2018/03/21 03:02

以下のようなjsを書きました。

function aaa(name, age) { aaa.test = name; aaa.name=1; console.log(aaa.test); console.log(aaa.name); } aaa(1,2);

結果は

1 aaa

です。

aaa関数の引数と同じ名前のオブジェクト(aaa.name)を作ると、1を代入しても代入されていないようですがこれはどうしてでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

根本的にコンストラクタを誤解しています.

あなたが提示したコードは単なる関数の呼び出しであり, 各行の意味合いは次のとおりです.

JavaScript

1//function宣言により変数aaaにFunctionオブジェクトが割り当てられる 2function aaa(name, age) { 3 aaa.test = name;//Functionオブジェクトaaaにプロパティtestを設定している 4 aaa.name=1;//Functionオブジェクトaaaの読み込み専用プロパティnameに値を設定しようとした 5 console.log(aaa.test);//aaa.testにはnameの内容が入っている→1 6 console.log(aaa.name);//aaa.nameには関数としての名称aaaが入っている.→aaa 7} 8aaa(1,2);

一方コンストラクタ関数new演算子と共に用いられることでオブジェクトを生成します.

JavaScript

1function Person(name, age){ 2 //コンストラクタ関数内部では生成したオブジェクトに変数thisでアクセスできる 3 //NOTE:この処理をオブジェクトの初期化と呼ぶ 4 this.name = name; 5 this.age = age; 6} 7 8//new演算子を付けてコンストラクタ関数を呼ぶとオブジェクトが返される. 9var person = new Person("山田太郎", 20); 10 11//オブジェクトを使う 12console.log("name", person.name);//name: 山田太郎 13console.log("age", person.age);//age: 20

NOTE:普通の関数とコンストラクタ関数を見分ける方法は?

これらはいずれもfunction宣言等により定義されるため, どちらの意味合いで使っているのかはコードの文脈を読み解くしかありません. が, 次のように使い分けられていることが多いです.

  • 通常の関数は名称が「動詞+目的語」として定義されており, 先頭が小文字である.

例)readBook 「本を読む」関数であることが判る

  • コンストラクタ関数の名称はものの名前(カテゴリ)がほとんどであり, 先頭が大文字である.

例)Book 「本」を表すオブジェクトを返すコンストラクタ関数であることが判る

またコードの中で変数thisに対し様々な処理を行っている場合はコンストラクタ関数である可能性が高くなります.(function.bindメソッドでthisを束縛している場合を除く)

なおこれでは使い勝手が悪いため, JavaScriptの新版ではコンストラクタ関数専用のclass宣言が追加されています.

投稿2018/03/21 03:31

編集2018/03/21 05:10
defghi1977

総合スコア4756

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kantowebmanager

2018/03/25 13:08

このたびはありがとうございます。 よく読ませていただいて自分の力にしていきたいです。
guest

0

関数のnameプロパティが読み取り専用だからだと思います。

【Function.name - JavaScript | MDN】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/name

投稿2018/03/21 03:25

kei344

総合スコア69400

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kantowebmanager

2018/03/25 13:09

ありがとうございます。 まだ復習が足りないのでもう一度読み返して調べてみます。
guest

0

ベストアンサー

こんにちは。

以下は、kei344さんのご回答をコードを書いて検証するものになります。

説明を分かりやすくするために、aaa を以下のような中身が空の関数として定義します。 

javascript

1function aaa(name, age) { 2 3}

この aaa は、name というプロパティを初めから持っており、 その値は "aaa"という文字列です。

javascript

1console.log(aaa.name); // "aaa" と表示される。 2 3console.log(aaa.name.constructor); // String() あるいは、[Function: String] 等と表示される。

さらに aaanameプロパティは変更することができません。
それはgetOwnPropertyDescriptorを使って、以下のようにして確かめられます。

javascript

1var desc = Object.getOwnPropertyDescriptor(aaa, 'name'); 2 3console.log(desc);

上記を実行すると desc の内容が以下であることが分かります。

{ value: 'aaa',

   writable: false,
enumerable: false,
configurable: true }

このように writableが false なので、name を書き換えることができません。

javascript

1aaa.name = 'bbb'; 2 3console.log(aaa.name); // => やはり、 "aaa"と表示される。

もし、aaa.name を書き換えたいのならば、以下のようにして、name のwritable属性 に
true を設定します。

javascript

1Object.defineProperty(aaa, 'name', { writable: true });

こうしておいて、再度

javascript

1desc = Object.getOwnPropertyDescriptor(aaa, 'name'); 2 3console.log(desc);

とすると、desc の内容が以下

{ value: 'aaa',

   writable: true,
enumerable: false,
configurable: true }

のように、 writable が true になっているのが分かります。こうしておいてから、
aaa.name に別の文字列を代入することができます。

javascript

1aaa.name = 'bbb'; 2 3console.log(aaa.name); // => "bbb" と表示される。

  
以上の検証コードを以下に上げておきました。

https://jsfiddle.net/jun68ykt/so1u6nsa/6/

補足

関数オブジェクトに name というプロパティがあって、それは
デフォルトでは書き込みできない、ということは覚えておけばよい
として、質問者様にとってより重要なのは、

aaa.name にどうして、1を代入できないのか?」
という質問のタイトルとして、
「コンストラクタがわかりません。」
というのは適切ではない、ということを理解すること

かなと思います。
ですので、 defghi1977さんのご回答も参考のうえ、コンストラクタの定義を
見直して、知識を整理されるとよろしいかと思います。

 
以上参考になれば幸いです。

投稿2018/03/21 04:30

編集2018/03/22 19:30
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kantowebmanager

2018/03/21 04:50

ありがとうございます。 writableが falseになっていて書き込み禁止にされているから代入してもすべて無効ということですね。 私は最初 function aaa(name, age) {}のように関数の引数として使った名前(nameとage)は、その関数の定義の中で「aaa.name=1;」のように使って代入することが禁止されているのかと思いましたが、そうではなくて「name」という名称がJavaScriptで事前に予約されている特別な意味を持った名前で代入禁止にされているということですよね? 実際function aaa(name, age) {}の部分をfunction aaa(testtest, age) {}にして「aaa.testtest=1;」にしてコンソール出力したら正常に1が表示されたのでそのように思いました。 ちなみにですがコンストラクタを勉強したくて調べていたらいきなり function aaa(name age) { aaa.name = name; } のような書き方がされていてこんな書き方があるのかと思ってこれがコンストラクタなのかと思いました。 コンストラクタは関係なかったということだったんですね。 引き続きコンストラクタの学習を続けます。
jun68ykt

2018/03/22 23:26 編集

こんにちは。 各論は後にして、最も重要と思われることを先に返答します。 > ちなみにですがコンストラクタを勉強したくて調べていたらいきなり > function aaa(name age) { > aaa.name = name; > } > のような書き方がされていて とのことですが、お調べになって参考にされたその資料は、 少なくともwebstrerさんに > これがコンストラクタなのかと思いました。 という誤った理解をさせてしまっている点において、 あまり良質なものではないと思います。 webstrerさんのこれまでのJavascriptに関するご質問を拝読すると、 比較的、言語の核となる部分に対する疑問をご投稿されていると思いまして、 それはとても良いことなので、その 「基礎をきちんと理解をしたい」 という意欲を効果的に学習成果として反映させるために、 良質な基本書(※入門本ではありません。)を傍らに 置いて学習されることをお勧めします。 別のご質問で、私の回答に書かれたコメントにも >学習し始めのときほどあまりにもわからないことが多すぎて細かいところが気になってしまうというというのをこれまでも幾度となく経験してきました    とありましたが、    > 細かいところが気になってしまう    ことは、気にならない人に比べたらセンスがよいとも言えます。 ただ、その気になっている状態がフラストレーションになって 学習意欲を低下させないようにするための方法の一つとして    > 細かいところが気に なったら、この本の該当部分を読めばいい。 と思える、信頼のおける本格的な基本書(※繰り返しになりますが、 入門書ではありません。)を手元に置いておくことをお勧めします。 初めはその本を読むのではなく、辞書として置いておくつもりで かまいません。 (具体的に、このような用途でどの本がいいかで迷うようで あればお答えします)      以下、各論についての回答です。 > 「name」という名称がJavaScriptで事前に予約されている特別な意味を持った名前で代入禁止にされているということですよね? はい。 そう考えて、”当たらずとも遠からず”という感じです。 "当たらず" な部分がどこかといえば、 > JavaScriptで事前に予約されている という理解の仕方が正確ではないところです。 JavaScriptの(仕様の元になっているECMAScriptの)予約語は以下に出ています。 予約語 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Reserved_Words 上記を見ると、 "name"という語が予約語として指定されて いないことが分かると思います。   では、   function aaa(name, age) { }    によって生成される aaa の nameプロパティはどこで作られるかといえば、 上記のコードからは、Function のインスタンスオブジェクトである aaa が 生成されるわけですが、その生成過程で name プロパティが付与され、 この場合は、nameプロパティには "aaa"という文字列が設定されることになります。 上記の説明で、「この場合は、」と書いたのは、関数オブジェクト、すなわち、 Functionのインスタンスが生成されるときに、そのnameプロパティに 別の文字列が入ることもあるからです。 その一例として、私の手元に入っているnodeのインタプリタから、 与えられた引数xを2乗して返す関数を、Function コンストラクタを new することで作成して、sq という変数に入れて実行し、nameプロパティを 確認したものが以下です。 [ykt68@macbook15 ~]$ node -v v9.7.1 [ykt68@macbook15 ~]$ node > var sq = new Function("x", "return x * x"); undefined > sq instanceof Function true > sq(1) 1 > sq(2) 4 > sq(3) 9 > sq.name 'anonymous' > 上記のように、 sq.name には、「匿名」という意味の "anonymous"という文字列が入っています。 関数オブジェクトが生成されるときに、(どのような値が設定されるかは状況によるとしても、) nameプロパティが設定されることは理解されたと思いますが、これと同様に、JavaScriptが 標準で用意している型のオブジェクトに、特別な用途のプロパティが自動的に付与される例は 他にもあります。 たとえば、 var a = [1, 2, 3]; として生成される配列オブジェクトの a には、length プロパティが自動的に 付与されており、これには配列の長さが入っています。 console.log(a.length); //=> 3 先ほどの関数オブジェクト aaa の name プロパティも、配列のlengthと同じで、 それが作られるときに付与されるプロパティです。 (そして、配列オブジェクトの lengthプロパティもまた予約語ではありません) コンストラクタとは何か? ということと、関数オブジェクトにも Functionという コンストラクタがあるということを理解できていれば、 function aaa() { } と関数宣言を書いたときに、 aaa.name プロパティが自動的に設定されることも Functionコンストラクタがインスタンスを作るときに、nameプロパティを付与するのだな。 と確度の高い推定をすることができます。 (この推定を本当に確かめるには、JavaScriptインタプリタのソースを読むしかありません) JavaScriptをマスターするのに、コンストラクタと関数の理解はとても重要で、 コア中のコアです。ですので、冒頭申し上げたように、今後の学習のために 参照されている資料を、基本を身につけるために定評のある良書に変えることを お勧めしたいと思います。
kantowebmanager

2018/03/25 13:08

遅くなってすみませんでした。 ご返信誠にありがとうございます。 まだ自分で復習や検証ができていなくて頭が整理できていないのですが自分の手でもやってみたいと思います。 最近はwebで学習しているのですが独習JavaScriptという本も持っていてこちらも活用しながら進めていきたいと思います。 コンストラクタはやはりjsのコア部分になるんですね。 今の所、コンストラクタとクロージャを理解しようと思っています(文献を読んでいてもこの2つの用語の意味がわからないときついですし。。)。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問