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

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

ただいまの
回答率

88.04%

JavaScriptの処理結果をうまく説明できない

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 741

score 16

初めて質問をさせていただきます。
先週、JavaScriptを独学で学び始めたド素人です。
専門用語の使い方がよくわからないため、他人に教える際に自分が正しく伝えられるのかが心配です。

下記に一つ例を挙げるので、説明が伝わるのか見ていただきたいです。

例の説明は、ネットなどで調べながら自分なりに解釈したものを記述しています。
参考として見ていたコードがあったのですが、解説はついておらず、処理結果がなぜコンソールされた結果の通りになるのかがわからなかったものを自分なりに解釈しました。

以下の点を見ていただけると幸いです。

1. 解釈が正しいのか
2. 説明は伝わるのか
3. 用語の使い方は正しいのか

3番目が特に理解が曖昧なので、何を言っているのか伝わらない、壊滅的な状態だと思っています。

よろしくお願いいたします。

該当のソースコード

const x = {
  a: 1,
  b: 2,
}

Object.keys(x).forEach(y => {
  console.log(`${y}: ${x[y]}`);
});

説明

処理を上から順に説明していきます。

①定数xに対して、「a: 1」と「b: 2」の二つのプロパティをオブジェクトとして代入。

const x = {
  a: 1,
  b: 2,
}


②オブジェクトxからKeyのデータ値(a, b)を取ってくるよう設定。

Object.keys(x)


③配列(Object.keys(x))から要素を一つずつ取ってくるよう設定。

.forEach


④関数名をyとし、テンプレートリテラル(${y}: ${x[y]})を出力処理するように、アロー関数を用いてテンプレートリテラルを戻り値として設定。

(y => {
  console.log(`${y}: ${x[y]}`);
});


⑤「(オブジェクトxのKeyのデータ値): (定数xの配列数)」をテンプレートリテラルを使って出力。

console.log(`${y}: ${x[y]}`);


以上です。
駄文ですが、ご指摘の程、よろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+4

総評としては、英語を何も知らない初心者が、
英和辞典を使いながら英文を噛み砕いて覚えようとしているみたいな印象です。

それはそれで力がつく重要な事なので続けてください。
ただし、他人に説明するならば通訳さんクラスの抽象化・理解が必要になります。

その視点で質問文をざっくりと解説するとこんな感じの文章が模範解答になるんじゃないかと思います。

const x = {
  a: 1,
  b: 2,
}

Object.keys(x).forEach(y => {
  console.log(`${y}: ${x[y]}`);
});

プロパティa, bを所持する定数xを準備しておく。
定数xの各プロパティ名をプロパティ名: プロパティ値の対応表的な文字列に変換し、コンソール上に出力する。

ロジックとしては、
Object.keysを利用して定数xのプロパティ名の配列を生成する。
そのまま.forEachメソッドを実行して各プロパティ名から、
定数xのプロパティ値を参照してテンプレート文字列を駆使して文字列を生成。
そのままconsole.logの引数に入れて実行する。

推敲を重ねていけばもっと綺麗な日本語になるでしょうが、
こんな感じの流れの説明になるはずです。


コードは文章です。
日本語でも英語でも単語そのものを文から切り離した瞬間に意味合いが変わってしまうように、
コードも一箇所で切り出すと意味が通じなくなります。

そういう意味で今回切り出した断片的なコード辺を個別に翻訳するとこういった文章になります。

const x = {
  a: 1,
  b: 2,
}

定数xを下記の2つのプロパティを所持するオブジェクトとして定義する

  • aプロパティ: 値1
  • bプロパティ: 値2
Object.keys(x)

xのプロパティ名を抜き出し配列に変換する。

.forEach

左辺のオブジェクトのforEachプロパティを参照する。

(y => {
  console.log(`${y}: ${x[y]}`);
});

アロー関数を定義する。
アロー関数の中身はy引数と、xオブジェクトのyプロパティにアクセスしテンプレート文字列で文字列に変換したものを画面出力する。


答え合わせ

①定数xに対して、「a: 1」と「b: 2」の二つのプロパティをオブジェクトとして代入。

日本語の問題で「オブジェクトとして代入」は意味不明になってます。
主体となる文章は「定数xにオブジェクトを代入」で、プロパティの説明等は修飾と捉えるべきです。

②オブジェクトxからKeyのデータ値(a, b)を取ってくるよう設定。

模範解答は少々意地悪でしたね。
ですが「データ値(a, b)を取ってくる」では意味不明です。
Object.keys)は引数のオブジェクトが所持しているプロパティ名だけをピックアップして新しい配列を作るものです。
なのでコードで書けば["a", "b"]が戻り値として返ってきます。

これらの情報はaやbのプロパティの実際の値(1や2)が捨てられてしまっています。
なので「プロパティ名の配列に変換する」などという表現を使うべきでしょう。

③配列(Object.keys(x))から要素を一つずつ取ってくるよう設定。

同じく模範解答が意地悪でしたね。
Object.keys(x).forEach(fn)と一息に言った場合と、
個別に区切って説明をすると全く意味合いが変わります。

JavaScriptではプロパティとメソッドは紙一重の存在です。
オブジェクトのプロパティに関数を代入した場合のみメソッドとして取り扱い、その他の値が入っている場合はプロパティと呼びます。
関数やメソッドを実行するにはお尻に丸括弧を付けることで実行が可能です。

Object.keysの実行結果はArrayに決まっているので、
決め打ちでforEachプロパティを見に行けば関数が入っている(メソッドとわかる)に決まっているのですが、
文脈をそこで切るとプロパティかメソッドかの情報がシュレディンガーの猫のように隠されてしまいます。

また.forEachは取ってくるものではありません。
「取ってくる」は戻り値を利用することを強く意識させるので表現としては不適切です。

正しくは「配列の各要素に対して、引数の関数を実行する」という意味があるので、
これを元に表現を追加して文章を作りましょう。

④関数名をyとし、テンプレートリテラル(${y}: ${x[y]})を出力処理するように、アロー関数を用いてテンプレートリテラルを戻り値として設定。

そこで切ってしまうと、「アロー関数の定義」の意味しか残らなくなります。
.forEach()で包んで、「アロー関数を定義して各配列の要素で実行」などとした方が良いでしょう。

確かにアロー関数は用いていますが、
「テンプレートリテラルを戻り値として設定」は大嘘です。
中で直接console.log実行しとるやん。
テンプレートリテラルを作成してconsole.logの引数として指定してあげてるだけです。

⑤「(オブジェクトxのKeyのデータ値): (定数xの配列数)」をテンプレートリテラルを使って出力。

「オブジェクトxのKeyのデータ値」は駄目、これはxのプロパティ名です。
「定数xの配列数」ってなんやねん、お前1か2かの数値やろ。

また、日本語で説明したいなら目的を書いたほうが良いでしょう。
説明するべき目的は「定数xのプロパティ名、対応する値を画面表示したい」のはずです。

テンプレート文字列という言葉を使いたいだけの小学生みたいな説明文になってしまいます。
一目で分かる文章にしたければ、「文字列を作って画面出力を行う」などと簡素に書いて、
次の行で詳細に説明するなどの工夫が必要です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/18 19:44

    ご回答ありがとうございます。
    ここまで丁寧な返答をいただけるとは思っておらず、とても嬉しく思っております。

    やはり随分と表現が違っていたんですね。
    私の文を読み、どのような印象を受けたのかも、とてもわかりやすかったです。笑
    一つ一つの用語の定義からかなり怪しい状態なのだと認識しました。
    復習をして、再度解説を読ませていただき、自分も同じ説明をできるようにします。

    NozomuIkutaさん、miyabi-sunのお二方とも、とても詳しく説明をしてくださっており、甲乙つけがたいご回答でしたが(なんだかかなり上から目線の言い方になってしまい申し訳ございません)、個人的に理解しやすく感じたmiyabi-sunに今回はベストアンサーをつけさせていただきたいます。
    また似たような質問をするかもしれませんが、その際にはよろしくお願いいたします。

    キャンセル

+3

少しずつ違うところがあります。
説明する相手のレベルがわかりませんが、参考までに説明を載せておきますので、質問があればコメントでおお願いします。


const x = {
  a: 1,
  b: 2
}

定数xに対して、「a: 1」と「b: 2」の二つのプロパティをオブジェクトとして代入。

変数xに、「a: 1」と「b: 2」という2つのプロパティを持つオブジェクトを代入する。

説明

まず、JavaScriptには、他のプログラミング言語でいうところの「定数」はありません。
constは、varletと同様に変数です。波括弧(ブロック{})が有効範囲です。
なぜ「定数」のイメージがあるのかといえば「変数が有効なスコープ内で再代入ができない」からです。

ブラウザ(Google Chromeがおすすめ)のデベロッパーツールのコンソールで、以下のコードを実行すると理解できます。

const x = 1
x = 2 // -> Uncaught TypeError: Assignment to constant variable.

上記のコードは、「constant変数(=variable)に(再)代入がある」とうエラーです。


Object.keys(x)

オブジェクトxからKeyのデータ値(a, b)を取ってくるよう設定。

オブジェクトxについて、キー(プロパティ名)を配列として取得する。

説明

Object.keys()は、引数に渡されたオブジェクトの、プロパティ名を配列として取得します。
fumi44さんの説明にあるのはObject.values()というメソッドです。

ちなみに、キーと値の両方を配列で取得したい場合、Object.entries()が使えます。

Object.keys(x)
// -> `[ 'a', 'b' ]` or `[ 'b', 'a' ]`

Object.values(x)
// -> `[ 1, 2 ]` or `[ 2, 1 ]`

Object.entries(x)
// -> `[ [ 'a', 1 ], [ 'b', 2 ] ]` or `[ [ 'b', 2 ], [ 'a', 1 ] ]`

補足(1):配列内の要素順は保証されていません(=定義した順番とは限らない)。
補足(2):3つのメソッドは、ブラウザにより対応状況が異なります。


.forEach(y => {
  ...
});

配列(Object.keys(x))から要素を一つずつ取ってくるよう設定。

Object.keys(x)で取得した配列について、forEach()メソッドを実行する。
forEach()メソッドは、第1引数に関数を受け取り、その関数の第1引数として配列の要素を渡し関数を実行する。これを配列のすべての要素に対して行う。

説明

説明のためにコードのまとまりを変えました。
以下のコードを見た方が理解できるかもしれません。

const valuesOfX = Object.values(x)

valuesOfX.forEach(function(value, index) {
  console.log(index, value) // -> 1回目: 0, 'a', 2回目: 'b'
})

補足(1):元のソースコードは、アロー関数を使用しています。アロー関数は、第1引数だけだと()を省略できます。
補足(2):forEach()の第1引数は関数であり、その関数の引数は、「要素、要素のインデックス、元の配列」です。


console.log(`${y}: ${x[y]}`);

「(オブジェクトxのKeyのデータ値): (定数xの配列数)」をテンプレートリテラルを使って出力。

「(オブジェクトxのキー):(オブジェクトxのキー)」をテンプレートリテラルを使ってコンソールに出力する。

説明

出力される内容が異なります。また、「定数xの配列数」は前述の説明にあるように間違いです。
もとの説明にあるような文字列を出力したい場合、以下のソースコードである必要があります。

const x = {
  a: 1,
  b: 2
};

Object.values(x).forEach((value, index) => {
  console.log(`${value}: ${index}`);
});

もし、「xのキーと値を文字列で出力する」ことを意図しているのであれば、ソースコードは以下のようになります。

const x = {
  a: 1,
  b: 2
}

Object.entries(x).forEach(entry => {
  const key = entry[0]
  const value = entry[1]

  console.log(`${key}: ${value}`);
});

補足(1):テンプレートリテラルは、ブラウザにより対応状況が異なります。


追記(2019/3/19)

think49さん

constまわりは訳語や用途によって意味がややこしいのですが、自分の理解している限り以下の通りです。

Variable(変数) の定義(MDNより引用

A variable is a named location for storing a value.

-> varletconstのすべてがvariable(変数)

Declarations(宣言)の定義(MDNより引用

var 
Declares a variable, ...
let
Declares a ... variable, ...
const
Declares a ... constant.

-> varletはvariable(変数)、constconstant(定数)

つまり、一言で言えば「変数」「定数」という用語が使用されている文脈が異なります。
定義上、3つすべてが変数であり、宣言上(宣言するものは)、2つが変数で1つが定数です。

ただ、think49さんが言う通り、constで宣言したものの参照は変更できませんが、参照先の中身(オブジェクトのプロパティなど)は変更可能なので、使用上も一部「変数」的な振る舞いをすると言えるかもしれません。

Object.freeze()Object.defineProperty()でread-onlyなプロパティは作れますが、もはや「宣言」ではないので、、、

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/18 13:16

    > JavaScriptには、他のプログラミング言語でいうところの「定数」はありません。
    「定数ではない根拠」はGoogle Chromeのエラーメッセージでしょうか。
    仕様では variables と記載があるので、確かに変数ですが、「再代入不可なら定数と認識して差し支えないのでは」ととらえる人がいてもおかしくはないので、定数と変数の具体的な違いに言及されると嬉しいです。
    http://www.ecma-international.org/ecma-262/9.0/#sec-let-and-const-declarations
    (実際の動きに照らし合わせるなら、「オブジェクトのプロパティを改変可能=変数」になるのでしょうか)

    キャンセル

  • 2019/03/18 19:45

    ご回答ありがとうございます。
    ここまで丁寧な返答をいただけるとは思っておらず、とても嬉しく思っております。

    表現がこんなに違っていたとは…プログラミングはおもしろいですねー。
    先に進めるのではなく、もう一度用語の定義から見直してみます。
    復習のため、何度も読ませていただきますね。

    NozomuIkutaさん、miyabi-sunのお二方とも、とても詳しく説明をしてくださっており、甲乙つけがたいご回答でしたが(なんだかかなり上から目線の言い方になってしまい申し訳ございません)、個人的に解説がわかりやすかったmiyabi-sunに今回はベストアンサーをつけさせていただきたいと思います。
    また質問をした際には、ご回答をいただけるととても嬉しいです。
    またよろしくお願いいたします。

    キャンセル

  • 2019/03/19 01:20

    >fumi44さん
    解決したようでよかったです。ベストアンサーは、ご自分の考えで決める部分ですし、特に謝ったりする必要はないと思いますよ。誰かが質問して、誰かが答える、基本それだけのサービスで、ポイント制度などはおまけですし。

    キャンセル

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

  • ただいまの回答率 88.04%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る