teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

3

補足説明追加

2018/12/07 08:42

投稿

miyabi-sun
miyabi-sun

スコア21461

answer CHANGED
@@ -76,6 +76,7 @@
76
76
  [JavaScript の配列のシャローコピーに使えるメソッド3つ(+ 1つ)とその使い分け - おかかウェブ](http://okakacacao.wpblog.jp/technology/javascript-array-shallow-copy)
77
77
 
78
78
  回答文に上がっている解決策はこのシャローコピーやディープコピーの手法です。
79
+ (この手法はどちらもちゃんとGASで使える事を確認しています)
79
80
 
80
81
  - `JSON.parse(JSON.stringify(...))`: 簡易的なディープコピー
81
82
  - `array.slice()`: スマートなシャローコピー
@@ -85,7 +86,7 @@
85
86
  【おまけ】【修正版】関数作ってワンライナーで頑張る
86
87
 
87
88
  一撃で行けると思ったのですが、どうもGASはJavaScript1.6ベースでできており、
88
- ECMAScript5や6の便利機能はほぼ使えなよう
89
+ ECMAScript6の便利機能は全滅、5も動作が怪し、注意してください
89
90
 
90
91
  参考サイト
91
92
 
@@ -95,6 +96,7 @@
95
96
 
96
97
  そもそも配列の要素を一気につくるイディオムがES6に頼る事になるので、
97
98
  それに頼れないとなると一気に微妙化しますが、こんな感じで配列作る関数を用意して動作させることになります。
99
+ 下記のコードは調査済みで動作します…が、`array.slice()`の方が明らかに筋が良いですね。参考までにどうぞ。
98
100
 
99
101
  ```JavaScript
100
102
  function myFunction() {

2

回避策を記載

2018/12/07 08:42

投稿

miyabi-sun
miyabi-sun

スコア21461

answer CHANGED
@@ -82,19 +82,33 @@
82
82
 
83
83
  ---
84
84
 
85
- 【おまけ】
86
- ぁ、n個の要素を持つ配列ならディオム覚えれば1行すね。
85
+ 【おけ】【修正版】関数作ってワンラナー頑張る
87
86
 
88
- ```
89
- n = 11;
90
- // 全て0埋めしn個配列
87
+ 一撃で行けると思ったのですが、どうもGASはJavaScript1.6ベースでできており、
91
- console.log(Array(n).fill(0));
88
+ ECMAScript5や6の便利機能はほぼ使えないようです。
92
- // (11) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
93
- var maze = Array(n).fill(0).map(() => Array(n).fill(0));
94
- console.log(maze);
95
- // (11) [Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11)]
96
- ```
97
89
 
98
- `Array(n).fill(0)`自体が0埋めされたn個の配列を新しく作るというディオムであり、
99
- [Array.prototype.map](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map)は冒頭に「その結果からなる新しい配列を生成します。」と書いてあるように、
100
- 新しい配列を作っているので質問文の問題は解消された状態になっています。
90
+ 参考サ
91
+
92
+ - [What functions do Arrays in Google Apps Script support?](https://stackoverflow.com/questions/39317252/what-functions-do-arrays-in-google-apps-script-support)
93
+ - [Basic JavaScript features](https://developers.google.com/apps-script/guides/services/#basic_javascript_features)
94
+ - [JavaScript 1.6 の新機能 - MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/New_in_JavaScript/1.6)
95
+
96
+ そもそも配列の要素を一気につくるイディオムがES6に頼る事になるので、
97
+ それに頼れないとなると一気に微妙化しますが、こんな感じで配列作る関数を用意して動作させることになります。
98
+
99
+ ```JavaScript
100
+ function myFunction() {
101
+ var n = 11;
102
+ var array = function (num) {
103
+ var arr = [];
104
+ for (var i = 0; i < num; i++) {
105
+ arr.push(0);
106
+ }
107
+ return arr;
108
+ }
109
+ var maze = array(n).map(function () { return array(n); });
110
+ Logger.log(maze);
111
+ }
112
+
113
+ // [18-12-07 17:36:31:549 JST] [[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]
114
+ ```

1

おまけ追加

2018/12/07 08:37

投稿

miyabi-sun
miyabi-sun

スコア21461

answer CHANGED
@@ -14,9 +14,13 @@
14
14
 
15
15
  ---
16
16
 
17
- JavaScriptの世界では、`{name: "hoge"}`というオブジェクトや、`[1, 2, 3]`という配列を変数に代入した時、変数は「アドレス番地の参照」格納されます。
17
+ JavaScriptの世界では、`{name: "hoge"}`というオブジェクトや、`[1, 2, 3]`という配列を宣言した時、初めてメモリ空間上オブジェクト/配列生成されます。
18
+ 変数や引数として使う時は全て「メモリ空間のアドレス番地」でやりとりされます(参照やポインタ等と表現されます)
19
+ 変数に代入された時、目には見えませんしとりだせませんが、オブジェクト/配列の実体ではなく、アドレス番地という数値が代入されていると考えてください。
20
+
18
21
  `[1, 2, 3] === [1, 2, 3]`の結果が`false`になるのは、比較演算子でオブジェクトや配列を比較した場合、配列そのものではなく、「アドレス番地」での比較になります。
22
+ 1行内に配列宣言が2個ありますので、メモリ空間上に配列2個作られ、それぞれのアドレス番地が帰って来ます。
19
- メモリ空間上に配列2個作れば別々のアドレス番地2個が払い出されので一致しというカラクリす。
23
+ 々のアドレス番地は当然異な比較結果も`false`にというカラクリになっています。
20
24
 
21
25
  これがどう質問文に影響してくるかを見ていきましょう。
22
26
 
@@ -42,10 +46,30 @@
42
46
  `maze.push(array)`としていますが、arrayには配列のアドレス番地が入ってます。
43
47
  つまり、11回繰り返した結果mazeは`[arrayのアドレス番地, arrayのアドレス番地, arrayのアドレス番地, ...]`という配列になります。
44
48
 
45
- 質問文のコードはメモリ空間上にmazeとarrayのコピー11個、計12個の配列が存在して欲しいすが、
49
+ 理想はメモリ空間上にmazeとarrayのコピー11個、計12個の配列が存在して`maze`中身は`[array1, array2, array3 ...]`という風になって欲しいはずですが、
46
- 実際にはmazeとarray1個ずつ、計2個の配列しか存在していない事になり
50
+ 実際にはmazeとarrayの計2個の配列しか存在していません
51
+ そりゃarrayの値を1個弄ったら全部変化するよね……という訳で、そのコードは欠陥となるわけです。
47
52
 
53
+ 配列は基本的に宣言したタイミングで作られるので、
54
+ 素直に解決するなら多重ループに変更してこういったコードになるでしょう。
55
+
56
+ ```JavaScript
57
+ function main (n) {
58
+ n = 11;
59
+ var maze = [];
60
+ for (var i = 0; i < n; i++) {
61
+ // ループの中で新しい配列を作って育てる
62
+ var array = [];
63
+ for (var j = 0; j < n; j++) {
64
+ array.push(0);
65
+ }
66
+ maze.push(array);
67
+ }
68
+ }
69
+ ```
70
+
71
+ ですが、ループやif文のネストって理解が難しくなるのでできれば避けたいですよね。
48
- なのでarrayの複製をメモリ空間上に作るテクニック必要となます。
72
+ そういった時に、メモリ空間上に配列の複製をってしまう手法
49
73
  これをシャローコピーやディープコピーと呼びます。
50
74
  詳しい記事を見つけたので、具体的な方法はこちらを読んでみてください。
51
75
 
@@ -54,4 +78,23 @@
54
78
  回答文に上がっている解決策はこのシャローコピーやディープコピーの手法です。
55
79
 
56
80
  - `JSON.parse(JSON.stringify(...))`: 簡易的なディープコピー
57
- - `array.slice()`: スマートなシャローコピー
81
+ - `array.slice()`: スマートなシャローコピー
82
+
83
+ ---
84
+
85
+ 【おまけ】
86
+ まぁ、n個の要素を持つ配列ならイディオム覚えれば1行ですね。
87
+
88
+ ```
89
+ n = 11;
90
+ // 全て0埋めしたn個の配列
91
+ console.log(Array(n).fill(0));
92
+ // (11) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
93
+ var maze = Array(n).fill(0).map(() => Array(n).fill(0));
94
+ console.log(maze);
95
+ // (11) [Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11)]
96
+ ```
97
+
98
+ `Array(n).fill(0)`自体が0埋めされたn個の配列を新しく作るというイディオムであり、
99
+ [Array.prototype.map](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map)は冒頭に「その結果からなる新しい配列を生成します。」と書いてあるように、
100
+ 新しい配列を作っているので質問文の問題は解消された状態になっています。