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

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

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

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

Q&A

解決済

3回答

340閲覧

js ソートの実行順序について

wp-h

総合スコア135

JavaScript

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

2グッド

3クリップ

投稿2018/01/27 13:23

sort関数の実行順序について疑問があります。
下記のようなコードがあった場合、ブラウザはどのような解釈をしているのでしょうか?

(function(){ 'use strict'; var array = { 1:['c','a','d','b'], 2:['aa','cc','bb'], } console.log(array[1]);//["c", "a", "d", "b"]① console.log(array);//1:["a", "b", "c", "d"]② array[1].sort(); console.log(array[1]);//["a", "b", "c", "d"]③ console.log(array);//1:["a", "b", "c", "d"]④ })();

①の箇所と③の箇所は自然な順序に思えますが
なぜ②の時点でarray[1]が既にソートされているのでしょうか?

以下の環境で検証しました
Crome 63.0.3239.132
Safari 11.0 (12604.1.38.1.7

defghi1977👍を押しています

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

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

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

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

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

guest

回答3

0

ベストアンサー

なぜ②の時点でarray[1]が既にソートされているのでしょうか?

ブラウザが②を実行しているとき、array[1]はまだソートされていませんが、あなたが②の結果を確認しているのは、おそらくソートされた後です。きっと、①の結果も②と同じ状況になっているでしょう。

console.logは、ブラウザのコンソールにarray[1]を表示します。
表示されたarray[1]は「出力された当時のarray[1]」ではなく、「いまのarray[1]」です。
「出力された当時のarray[1]」を出力するには、↓のコードのようにJSONの文字列にしてしまうか、array[1].slice()のようにしてコピーをつくりましょう。

javascript

1console.log(JSON.stringify(array[1])); 2console.log(JSON.stringify(array)); 3array[1].sort(); 4console.log(JSON.stringify(array[1])); 5console.log(JSON.stringify(array));

また、コンソールで1行づつ実行して確認しても、期待しているような結果が得られるはずです。


以下のコードで同じような状況を再現できます。

javascript

1var object = {a: 123, b: 123, c: 123}; 2console.log(object); 3object.a = 456; 4object.b = 456; 5object.c = 456; 6console.log(object);

ブラウザのコンソールに2回同じオブジェクトを出力します。それぞれ、クリックして中を確認してください。中身は同じになっています。

イメージ説明

投稿2018/01/27 14:04

編集2018/01/27 14:46
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

defghi1977

2018/01/27 14:34

それだ!コンソールに表示されているのはobjectのライブビューというわけだ
wp-h

2018/01/27 14:45

再現コードと確認手順まで詳細に載せていただいて助かりました! 正直文字だけでは..?状態だったので(^^;) 大変勉強になりました!ベントアンサーにさせていただきます
guest

0

破壊的と非破壊的

Array.prototype.sort破壊的です。
実行されれば元となった配列を直接書き換えます。

①の箇所と③の箇所は自然な順序に思えますが
なぜ②の時点でarray[1]が既にソートされているのでしょうか?

①の箇所が自然と思われるのでしたら、それは「破壊的な動作を望んでいる」ということになります。
逆に非破壊的なら、①②③④の全てでソート前の配列が出力されることになります。

何か根本的な部分で思い違いをしているように思われますので、一度、自分自身の考えを全て書きだして、矛盾がないか見直してみることをお勧めします。
ご自身で納得出来ないようでしたら、書き出した自身の考えをteratailへ寄せれば、どなたか気が付いた方が指摘してくれると思います。

Re: mercy5 さん

投稿2018/01/27 13:42

編集2018/01/27 13:42
think49

総合スコア18164

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

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

wp-h

2018/01/27 14:47

>>何か根本的な部分で思い違いをしているように思われますので、一度、自分自身の考えを全て書きだして、矛盾がないか見直してみることをお勧めします。 おっしゃる通りでした。 認識不足に気がつくことができました^^;ありがとうございます。
guest

0

以下は回答者の憶測が含まれています. 有力な根拠については不明です.

根拠を追加


以下は間違った解釈です.
console.logメソッドに直接オブジェクトを指定した場合の動作に原因があるように見受けられます.

console.logメソッドの動作を

  1. console.logメソッドが実行されると, WEBブラウザはログキューにその内容を保管する.
  2. スクリプトの実行が完了(もしくはタイマーによる出力?)するとログの内容をコンソールに出力する.

であると仮定すると, 1でconsole.logの引数としてオブジェクトへの参照を渡した際に, 2の過程で初めてオブジェクトが直列化されることになります. 従って, sortメソッド実行前にも関わらず, array[1]の内容がソート済みとなっているように見えるのです.


https://developer.mozilla.org/en-US/docs/Web/API/Console/log
によれば

A list of JavaScript objects to output. The string representations of each of these objects are appended together in the order listed and output. Please be warned that if you log objects in the latest versions of Chrome and Firefox what you get logged on the console is a reference to the object, which is not necessarily the 'value' of the object at the moment in time you call console.log(), but it is the value of the object at the moment you click it open.

要約
console.logで記録されるものはその時点でのオブジェクトに対する参照値であり, その時点でのオブジェクトの内部値ではない. なので, コンソールからログ内のオブジェクトにアクセスすると, その時点での値が表示される.

この問題はJSON.stringifyメソッドを適用する, もしくはtoStringメソッドを実装しておく(Arrayオブジェクトについて正しく動作している要因)等, ログの内容を文字列として固定することで回避できます.

JavaScript

1 (function(){ 2 'use strict'; 3 var array = { 4 1:['c','a','d','b'], 5 2:['aa','cc','bb'], 6 } 7 console.log(array[1]);//["c", "a", "d", "b"]① 8 console.log(JSON.stringify(array));//② 9 array[1].sort(); 10 console.log(array[1]);//["a", "b", "c", "d"]③ 11 console.log(JSON.stringify(array));//④ 12 })();

Text

1//コンソールでの出力結果 2Array [ "c", "a", "d", "b" ] 3{"1":["c","a","d","b"],"2":["aa","cc","bb"]} 4Array [ "a", "b", "c", "d" ] 5{"1":["a","b","c","d"],"2":["aa","cc","bb"]}

投稿2018/01/27 14:32

編集2018/01/27 14:48
defghi1977

総合スコア4756

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

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

wp-h

2018/01/27 14:43

検証にはconsole.logにそのままオブジェクトを渡しておおざっぱに確認することが多かったですが、今回の件で色々と考えさせられました。 console.logの出力にこんな仕組みがあったとは。勉強になります。
defghi1977

2018/01/27 14:51

いや, この動作知らんと結構危険. 今回みたいにログを追ってデバッグする際に悩む原因になりうる. 気が付かせてもらってこちらとしても感謝です.
KNaito

2018/03/06 04:48

これ、気付かずにはまりそうですね。手持ちの環境でテストしたところ、Firefox, Chrome, Safariでは今回のようにconsole.log後に修正された値が表示されました。node.js (9.5)やIEでは修正される前の値が表示されました。(Edgeは、オブジェクトとしか表示されず、オブジェクトの内部状態は表示されませんでした) 丁寧にチェックするときはstringifyをかけた方がよさそうですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問