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

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

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

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

Q&A

解決済

4回答

3947閲覧

concatの動作に関して

answer

総合スコア16

JavaScript

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

0グッド

0クリップ

投稿2016/06/23 16:50

検索サイトconcatを検索すると
http://www.kanasansoft.com/weblab/2009/04/javascriptconcat.html
上記ページが出てくるのですが、結局何を言っているのかがわかりません。
元々はconcatは負荷がかかるから使わないほうがいいという趣旨のページだったようですが、
その後の追記でそれを撤回しています。
結局は使用するブラウザや連結する配列の状況によって変わってくるから気にすることなく
concatを使って良いという解釈でよろしいでしょうか?

それと、もう一つ、
http://d.hatena.ne.jp/coppieee/20090424/1240595439
上記ページに書かれているソースコードで

var ary = [0,1,2];
var result = ary.concat();
result.push(3);
result.push(4);
result.push(5);

このようなものがありますが

var result = ary.concat();

これがよくわかりません。

var result = ary;

concatを使わなくてもいいような気がします。
この理由も知りたいです。わかる方がいましたら教えてもらえると助かります。

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

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

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

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

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

kei344

2016/06/23 16:59 編集

コードはコードブロックで囲んでいただけませんか? ```(バッククオート3つ)で囲み、前後に改行をいれるか、コードを選択して「</>」ボタンを押すとコードブロックになります。また、URLにはリンクを貼っていただけるとさらにありがたいです。
guest

回答4

0

ベストアンサー

非破壊的な関数は遅い

原則として「非破壊的な関数」は「破壊的な関数」よりも遅いです。
なぜなら「既存のデータ(配列)をコピーして新しく生成する処理」が余計にかかっているからです。
a.concat(b) ならば「a をコピーして新しく生成する処理」が push の処理に加えてあるので、concat はどうやっても push よりも遅いのです。
同じ理由で下記関数は非破壊的なので「遅い」です(思いつく範囲でとりあげただけなので他にもあるかもしれません)。

  • Array.prototype.slice
  • Array.prototype.concat
  • Array.prototype.map
  • Array.prototype.filter
  • Array.prototype.entries
  • Array.from

同じ理由で jQuery の関数はそのほとんどが「遅い」です。

  • jQuery(), $()
  • jQuery#filter
  • jQuery#slice
  • jQuery#toArray
  • jQuery#map

一般的に jQuery を使えば、新しいオブジェクトを生成して処理をするようコーディングしますが、もともとのオブジェクトをそのまま処理をする方が速い事は明白です。

破壊的/非破壊的

速度だけにとらわれると大事なことを見失います。

JavaScript

1var a = ['a', 'b', 'c'], 2 b = ['d', 'e', 'f']; 3 4console.log(a.concat(b)); // ["a", "b", "c", "d", "e", "f"] 5Array.prototype.push.apply(a, b); 6console.log(a); // ["a", "b", "c", "d", "e", "f"]

一見、同じ結果に見えますが、Array.prototype.push は破壊的なのでコードの順番を変えると意図しない動きとなります。

JavaScript

1var a = ['a', 'b', 'c'], 2 b = ['d', 'e', 'f']; 3 4Array.prototype.push.apply(a, b); 5console.log(a); // ["a", "b", "c", "d", "e", "f"] 6console.log(a.concat(b)); // ["a", "b", "c", "d", "e", "f", "d", "e", "f"]

重要なのは「変数 a に破壊的な処理をしても問題ないのか」という観点です。
筆者は「push を使うべき」というスタンスでしたので、この場合は破壊的な処理で問題なかったのでしょう。
しかし、「破壊的では困るケース」というものも存在するはずで、その場合に concat は有用です。

Array.prototype.fill

Array.prototype.fill を使うことでループ処理そのものをなくす事が出来ます。
ただし、数があまりに多いとコールスタックを使い切ってしまうようでループ回数を 90000 回にしたら、「RangeError: Maximum call stack size exceeded」の例外で実行できませんでした。

JavaScript

1'use strict'; 2var a = ['a', 'b', 'c'], 3 b = ['d', 'e', 'f']; 4var start = new Date(); 5Array.prototype.push.apply(a, Array.prototype.concat.apply(b, Array(79999).fill(b))) 6var end = new Date(); 7console.log(end.getTime()-start.getTime()); 8console.log(a.length); 9 10var a = ['a', 'b', 'c'], 11 b = ['d', 'e', 'f']; 12var start = new Date(); 13var push = Array.prototype.push; // 何度も呼び出すプロパティは変数にキャッシュしておく 14for (var i = 0; i < 80000; i++){ 15 push.apply(a, b); 16} 17var end = new Date(); 18console.log(end.getTime() - start.getTime()); 19console.log(a.length);

何度か試すと双方どちらとも一方を上回る場合もありますが、全体的には push に軍配が上がりそうです。
しかし、この場合は「配列を生成する必要があるのか」を設計段階で考えておく必要があります。
なぜなら、この配列は「index が 3 の倍数なら "d" を返す配列」なので計算方法さえ確立すれば配列を生成する必要がなくなるからです。
無駄にコードを書かない為にも、コードを書き始めるために設計指針を決めておく事が極めて重要です。

Re: answer さん

投稿2016/06/24 03:25

think49

総合スコア18156

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

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

0

var result = ary.concat(); は新たな配列を作るので、var result = ary; とは違います。

JavaScript

1var ary = [ 0, 1, 2 ]; 2var result = ary; 3console.log( ary ); //=> [ 0, 1, 2 ] 4console.log( result ); //=> [ 0, 1, 2 ] 5ary[ 0 ] = 'a'; 6ary[ 1 ] = 'b'; 7ary[ 2 ] = 'c'; 8console.log( ary ); //=> [ 'a', 'b', 'c' ] 9console.log( result ); //=> [ 'a', 'b', 'c' ] 10result = ary.concat(); 11ary[ 0 ] = 9; 12ary[ 1 ] = 8; 13ary[ 2 ] = 7; 14console.log( ary ); //=> [ 9, 8, 7 ] 15console.log( result ); //=> [ 'a', 'b', 'c' ]

**動くサンプル:https://jsfiddle.net/br4k2oku/

投稿2016/06/23 17:17

kei344

総合スコア69364

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

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

退会済みユーザー

退会済みユーザー

2016/06/23 17:22

なるほどです.
guest

0

回答ありがとうございます。
非破壊・破壊と言うのを初めて知りました。
また、通常は配列の値はコピーされていなく同じ所を見ていることも知りました。
今まではコピーしたものと思い込んで使っていました。これからは気をつけたいと思います。

投稿2016/07/07 16:22

answer

総合スコア16

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

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

0

Array.prototype.concat は 引数である配列を結合するというものです.

具体的には,

javascript

1var num1 = [1, 2, 3]; 2var num2 = [4, 5, 6]; 3var num3 = [7, 8, 9]; 4 5// 配列 [1, 2, 3, 4, 5, 6, 7, 8, 9] を生成; num1, num2, num3 は変化しません 6var nums = num1.concat(num2, num3); 7console.log(nums); //=> [1, 2, 3, 4, 5, 6, 7, 8, 9]

このように3つの配列を1つにまとめるようなとき利用するものです.

var result = ary.concat();

は問題なく動作しますが,意味はありません. 新しい配列のインスタンスを作っているので意味はあります.確認不足でした.
なぜならば,concat の引数が何もなく結合する配列がないからです・

質問のようなプログラムの例であれば,

var result = ary;

で問題ありません.

concat は 複数の配列を一つに前から順番にくっつけてるだけです.

Array.prototype.concat の 詳細は
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/concat
などを参照すれば良いと思います.

投稿2016/06/23 17:01

編集2016/06/23 17:24
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問