のくす牧場
コンテンツ
牧場内検索
カウンタ
総計:127,491,157人
昨日:no data人
今日:
最近の注目
人気の最安値情報

私的良スレ書庫

不明な単語は2ch用語を / 要望・削除依頼は掲示板へ。不適切な画像報告もこちらへどうぞ。 / 管理情報はtwitter
ログインするとレス評価できます。 登録ユーザには一部の画像が表示されますので、問題のある画像や記述を含むレスに「禁」ボタンを押してください。

元スレ+ JavaScript の質問用スレッド vol.122 +

JavaScript スレッド一覧へ / JavaScript とは? / 携帯版 / dat(gz)で取得 / トップメニュー
スレッド評価: スレッド評価について
みんなの評価 :
タグ : 追加: タグについて ※前スレ・次スレは、スレ番号だけ登録。駄スレにはタグつけず、スレ評価を。荒らしタグにはタグで対抗せず、タグ減点を。
レスフィルター : (試験中)
←前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 次へ→ / 要望・削除依頼は掲示板へ / 管理情報はtwitter
651 : Name_Not - 2015/02/02(月) 22:02:46.61 ID:???.net (+92,+29,-5)
じゃあなんで>>640は循環参照するのに>>646は循環参照しないんですか
652 : Name_Not - 2015/02/02(月) 22:10:41.44 ID:???.net (+59,+18,-1)
>>651
>>640は循環参照しません
653 : Name_Not - 2015/02/02(月) 22:14:09.02 ID:???.net (+70,+29,-196)
>>639
>>553を読めばわかる

> としとけばいいんでない
普通はやる必要がないこと。

removeEventListenerをするためには、名前を付けないといけない。
せっかくクロージャーを使って無名関数で
イベントハンドラを記述できるというのに、それは
newしたものを必ずdeleteしなければならない言語の
ようなもの。面倒くさい

> 一度しか実行されないハンドラは少数に限られるだろうから
それが昔のIEはページを移動してもメモリは解放されなかった。
だからどんどんブラウザが重くなっていった。

jQueryを使った場合は、クロージャーを使って本来あるべき姿のように
簡単に記述できていながら、メモリリークもしないようになっていた。
654 : Name_Not - 2015/02/02(月) 22:21:43.15 ID:???.net (+104,+29,-90)
>>641
> クロージャを少なくする設計には賛成だが、循環参照は関係ない

クロージャを少なくする設計なんて考えていたら、
全然問題がないEcmaScriptのmapやforEach、
underscoreやlodashの関数まで
クロージャー使わないほうがいいって勘違いするぞ。

問題は生存期間が長いイベントハンドラでクロージャーを使うと、
それが呼び出されたのと同じスコープの変数も使わないものであっても
生き残ってしまうっていうのが問題だろ。
だから逆にそのスコープ内の変数の方をなくしてもいい。
655 : Name_Not - 2015/02/02(月) 22:24:02.37 ID:???.net (+88,+21,-2)
>>654
要するに循環参照しない
656 : Name_Not - 2015/02/02(月) 22:30:08.17 ID:???.net (+9,-30,-139)
function foo() {
 var a = [巨大な配列];
 window.addEventHandler('load', function() { });
}

↑これを ↓こう書けばいいことは分かった

function onload() {
}
function foo() {
 var a = [巨大な配列];
 window.addEventHandler('load', onload);
}

巨大な配列は、onloadの中で参照しないからいいけど、
だけどonloadの中で参照したい変数があった時はどうするの?

つまり

function foo(value) {
 var a = [巨大な配列]; // これは要らないけど
 var b = value; // これは必要
 window.addEventHandler('load', onload);
}

function onload() {
 // ここでbを参照したい
}

クロージャーはこういうことが簡単にできるから
便利というめんもあるんだが
657 : Name_Not - 2015/02/02(月) 22:33:30.37 ID:???.net (+25,-30,-122)
>>656
jQueryを使えば簡単に実現できるよ。
jQueryなら追加のデータをイベントハンドラに渡せる。

その場合ならこのように書くことが出来る。

function foo(value) {
 var a = [巨大な配列]; // これは要らないけど
 var b = value; // これは必要
 $(window).on('load', {b: b}, onload);
}

function onload(event) {
 // ここでbを参照したい
 console.log(event.data.b);
}
658 : Name_Not - 2015/02/02(月) 22:35:51.29 ID:???.net (+35,+3,-13)
>>657
バッチリです。やっぱりjQuery便利やね
659 : Name_Not - 2015/02/02(月) 22:37:52.08 ID:???.net (+130,+22,-1)
>>655
循環参照はあまり関係ない
660 : Name_Not - 2015/02/02(月) 22:42:34.49 ID:???.net (+39,-30,-142)
この話を聞くと、Javaのクロージャーもどき(ラムダ)の
仕様は正解だったかもしれんな。

JavaScriptやいろんな言語のクロージャーはクロージャーの中から
aが見えてしまう。つまりイベントハンドラが生きてる間中、
イベントハンドラからaを参照しなくても、aが生き残ってしまう。

function foo() {
 var a = [巨大な配列];
 window.addEventHandler('load', function() {
  // ここからaが見える
 });
}

でも、javaのラムダは、aが見えない。
それがラムダはクロージャーではないと言われる理由なんだが、
ラムダであればクロージャーを使った場合のこの問題が無くなる。

クロージャーはあってもいいと思うんだけど
クロージャーとラムダの両方がほしい。そして必要ないならば
ラムダの方を使うべきだろう。
661 : Name_Not - 2015/02/02(月) 22:44:36.26 ID:???.net (+107,+29,-24)
>>659
循環参照ではなくて、ハンドラに使ったクロージャーは
生存期間が長いっていうのが問題だよね。

クロージャーの生存期間が短い場合は
クロージャーを使っても何の問題もない。
662 : Name_Not - 2015/02/02(月) 22:48:25.37 ID:???.net (+77,+29,-84)
>>661
そうだね。

(DOMとJavaScriptの)循環参照はメモリリークを招くという
古いIEのバグに関連する話で、
それを除けば循環参照してもよい。

ただ循環参照とハンドラの生存期間が長い問題は別の話で
ハンドラにクロージャーを使用すると、クロージャーから見える
そのスコープにある変数すべてがメモリ内に残ってしまう。
これはIEの循環参照のバグとは別の話。
663 : Name_Not - 2015/02/02(月) 23:02:52.28 ID:???.net (+3,-30,-143)
>>649
script要素が通信(コードを実行する)のは、
新しくscript要素を作成してdocumentに挿入したときと、srcも中身もないscript要素にsrcをセットしたとき。
http://html.spec.whatwg.org/multipage/scripting.html#the-script-element:prepare-a-script

<script src="hoge.js"></script> ← srcを変えても二度と通信しない
<script>alert(123);</script> ← 中身が書かれているので、srcを変えても通信しない
<script></script> ← srcも中身もないので、srcや中身を変えると一度だけ実行する

まあ簡単に言うと、一つのscript要素につきスクリプトは一回しか実行されないってことです。
664 : Name_Not - 2015/02/02(月) 23:04:36.05 ID:???.net (+114,+30,-41)
>>659
>>555で「↓なぜこれが循環参照になるのかというと」と明言している意図は?
初めから「循環参照は関係ない」と指摘しているのにあなたは枝葉にばかり拘っている
665 : Name_Not - 2015/02/02(月) 23:11:11.23 ID:???.net (+112,+30,-141)
>>664
循環参照にこだわるから、循環参照することは悪いのかって話になって
本当の問題が見えてこなくなる。

例えば、forEachでクロージャーを使っても循環参照する。だけどこれは問題ならない。
なぜならforEachのクロージャーの生存期間は凄く短いから。

本当の問題は、ハンドラであれば一般的にクロージャーの生存期間が長いことにある。
両方とも循環参照しているのに、一方は問題なくても一方は問題がある。
その理由は循環参照ではなくて、生存期間であるということに気づかないといけない。

それさえわかっていれば、クロージャーを使ってもいいことが理解できるはず。
本当の問題を理解せずに、わかりやすいからといってクロージャーは使ったらだめという
決まりを作ると、ルールだけが生き残ることになる。
666 : Name_Not - 2015/02/02(月) 23:32:27.61 ID:???.net (+13,-29,-79)
>>553
これremoveEventせずにDOMオブジェクトが消滅したらどうなるの?
ハンドラは開放されず永久に残リ続ける?
667 : Name_Not - 2015/02/02(月) 23:34:37.85 ID:???.net (+79,+29,-23)
>>665
そんなことは理解している
繰り返すが、>>555で「↓なぜこれが循環参照になるのかというと」と明言している意図は?
668 : Name_Not - 2015/02/02(月) 23:39:05.04 ID:???.net (+8,-30,-135)
>>666
> これremoveEventせずにDOMオブジェクトが消滅したらどうなるの?

DOMを消す時に、jQuery内部のcleanDataが呼ばれる。
cleanDataではDOMに関連づいたデータを全て消去する。
669 : Name_Not - 2015/02/02(月) 23:45:28.43 ID:???.net (+69,+29,-135)
>>647
> 繰り返すが、>>555で「↓なぜこれが循環参照になるのかというと」と明言している意図は?

古いIEでメモリリークする原因が、DOMとJavaScriptの間で
循環参照しているからだろ。「"DOMとJavaScriptの間で"循環参照してる」という
説明なしに、古いIEでメモリリークする理由を説明することは出来ない。

ここまでで一区切り。以下次の話として、

今の時代は古いIEは消えてしまったと考えていいものとする。
古いIEは消えてしまったのだから、循環参照しても問題ないよね?

そうは問屋が卸さない。
メモリリークの問題はなくなったが、
生存期間による不要なメモリ使用の問題は残っている。
これが今も起きてる注意すべき問題の話。
670 : Name_Not - 2015/02/02(月) 23:55:42.16 ID:???.net (+91,+29,-38)
そーゆーのってどうやってチェックするの?
タスクマネージャーを随時みるの?
671 : Name_Not - 2015/02/02(月) 23:57:37.11 ID:???.net (+70,+29,-40)
>>670
今はブラウザの開発者ツールに内蔵されてるよ。
昔は昔でそういうのを検出するプラグインがあった。
672 : Name_Not - 2015/02/02(月) 23:58:13.52 ID:???.net (+5,-29,-95)
>>668
MutationEventのようなもので監視してるわけではないのかな?
jQuery以外のAPIを叩いたり
ブラウザが勝手にDOMオブジェクトを消滅させた時はリークする?
673 : Name_Not - 2015/02/02(月) 23:58:56.47 ID:???.net (+54,+26,-22)
ダミーのデータを使ってわざと数十MB単位でメモリを使うように
すればタスクマネージャーでもわかると思う
674 : Name_Not - 2015/02/03(火) 00:05:11.18 ID:???.net (+3,-30,+0)
>>672
使われていないし、俺なら使わない

Mutation Event から Mutation Observers へ
http://standards.mitsue.co.jp/archives/001538.html
> “Detect DOM changes with Mutation Observers” で紹介されているように、
> DOM4 では Mutation Observers という新しいインタフェイス群が定義されました。
> これらを用いると、DOM2 Events で定義された Mutation Event を置きかえることができます。
>
> Mutation Event は数々の問題点を抱えていることが明らかになっています
> (策定中の DOM3 Events では該当箇所に警告文が記述されているほどです)。
> 例えばパフォーマンスに関わる問題があります。

jQueryでハンドラやデータを追加したのなら、jQueryで消さないとだめ。

ブラウザが勝手にDOMオブジェクトを消滅させることはないだろう。
(ページ移動は別。ページ移動時=unload時に解放していたはず)

jQueryで操作したならjQueryが使えるわけで、
それをjQuery以外で削除しようと思うことはあまりないと思うけどね。
675 : Name_Not - 2015/02/03(火) 00:56:19.38 ID:???.net (+55,-30,-212)
>>669
> 古いIEでメモリリークする原因が、DOMとJavaScriptの間で
> 循環参照しているからだろ。「
>>641で「巨大な配列がDOMでなければ循環参照しない」と指摘したはずだが、具体的に循環参照する「DOMオブジェクト」と「JavaScriptオブジェクト」は何だ?

function foo() {
 var a = [巨大な配列];
 window.addEventHandler('load', function() {
   alert(a.length);
   alert(foo.name);
 });
}

# 以下、戯言。
# 同じ内容を4回説明してようやく本題「循環参照しない」に入れたわけだが、何を答えてよいかわからない程の難問だったのかね…。
676 : Name_Not - 2015/02/03(火) 01:02:30.09 ID:???.net (+64,+29,-6)
>>675
それでお前が言いたいことは何なんだよ?w
678 : Name_Not - 2015/02/03(火) 01:06:41.53 ID:???.net (+45,-29,-61)
>>675
addEventHandlerって何だ、と思ったら>>555が出典だからか
普段から素のJavaScriptコードを書いているなら間違えるわけがないんだが
679 : Name_Not - 2015/02/03(火) 01:09:21.94 ID:???.net (+64,+29,-18)
>>678
すまんすまん。普段は書いてないよ。
jQueryの方を使うほうが楽なのでね。
681 : Name_Not - 2015/02/03(火) 01:34:23.64 ID:???.net (+37,-30,-210)
>>680
お、気づいたかw

そこは間違ったなって思っていたところなんだよ。
で、お前は気づいているよな?

windowsはグローバル変数だから当てはまるけど、
var elm = document.getElementById('id'); なら
ローカル変数になるから当てはまらないということを

今更ながら訂正すると

function foo() {
 var a = [巨大な配列];
 var elm = document.getElementById('id');
 elm.addEventListener('click', function() {
   alert(a.length);
   alert(foo.name);
 }, false);
}

これは循環参照する。
682 : Name_Not - 2015/02/03(火) 01:34:59.12 ID:???.net (-23,-1,-67)
>>680
> グローバルオブジェクト(DOM)はGCで正しくメモリを開放してくれるので考慮する必要がない事は覚えておいたほうがいい

古いIEの場合はそうとはいえない
684 : Name_Not - 2015/02/03(火) 01:48:06.99 ID:???.net (+72,+30,-24)
>>681
> お、気づいたかw
あなたが気が付いてないだけで>>641から同じ指摘を何度もしている
対してあなたは何を勘違いしたのか、無関係な返答を繰り返すばかり
あなたは気が付くのが遅すぎる
685 : Name_Not - 2015/02/03(火) 01:51:24.31 ID:???.net (+5,-27,-69)
>>682
「対象IEのバージョン」と「MSDNのソースURL」を教えてください
グローバルオブジェクト(DOM)を含む循環参照でもメモリリークするなら回避手段はないと思いますが、当時はどうしていたのでしょう?
686 : Name_Not - 2015/02/03(火) 02:45:03.87 ID:???.net (+64,+29,-65)
>>683
関数1つ作ったらグローバルスコープの参照カウンタは回るのでは?
関数スコープの外はすべてクロージャなんだから
687 : Name_Not - 2015/02/03(火) 04:35:20.99 ID:???.net (+68,+29,-65)
>>660
今のブラウザなら大丈夫なはず
自分で確かめてないからアレだけど、検証結果がこのスレ(の過去スレ)にも貼られていた

ただしハンドラ内でeval()を使ったりすると、そこを通るまでaが参照されるか不明なので
aは残ってしまうだろうね
688 : Name_Not - 2015/02/03(火) 07:47:22.67 ID:???.net (+11,-30,-200)
>>686
その考え方が認められるのなら「a(Script)→foo(Script)」も成立するのでは?

function hoge () {
 var p = document.createElement('p');

 function foo () {
  var div = document.createElement('div');
 }

 foo();
}

変数から上位スコープオブジェクトを参照可能とする場合、「div(DOM)→foo(Script)→p(DOM)」で循環参照が成立するが、勿論そんなことはない
ECMAScript 5 は関数スコープなので参照は関数単位で形成される
変数はスコープチェーンの過程で上位スコープを参照するだけ
689 : Name_Not - 2015/02/03(火) 08:17:28.90 ID:???.net (+50,+22,-68)
ローカル変数はスコープチェーン上で始めに一番近い関数スコープから参照するのでグローバルスコープの参照は発生しえないね
690 : Name_Not - 2015/02/03(火) 10:21:48.05 ID:???.net (+90,-30,-62)
a[1] == 1
このときaが配列じゃなかったら
Uncaught TypeError: Cannot read property '1' of null
ってエラーになりますが
a != null && a[1] == 1
って書くのが正解ですか?
691 : Name_Not - 2015/02/03(火) 11:33:33.93 ID:???.net (+5,-29,-15)
>>610
エラーになるべきなら、エラーになっていいだろ?

それともaがnullになることが有るのですか?
そしてaがnullだったら、
aには何も入れないという"仕様"ですか?
692 : Name_Not - 2015/02/03(火) 11:34:05.03 ID:???.net (+40,+9,+2)
>>610じゃなくて>>690
693 : Name_Not - 2015/02/03(火) 12:01:14.41 ID:???.net (+87,-29,-46)
たとえばさjsonpで取得した時ですよ
サーバから正常にデータを取得出来た時にaは配列になるけど
ただしいデータが送られて来なかった場合はaはnullになります
694 : Name_Not - 2015/02/03(火) 12:23:18.14 ID:???.net (+96,+29,-44)
>>693
正しいデータが送られてこなかった場合は、
エラーなんだから、エラーでいいじゃん?

なんで正しいデータが送られてこない時にまで
そのエラーを握りつぶして、無理やり動かすようなことをするのさ?
695 : Name_Not - 2015/02/03(火) 12:25:35.76 ID:???.net (+57,+29,-18)
正しいデータが送られてこなかったら
エラーが発生しましたって表示させるか、
ログなどに表示して、そこに来る前に処理を打ち切るんだよ
696 : Name_Not - 2015/02/03(火) 12:27:36.05 ID:???.net (+61,+26,-19)
本気でコード書いたらエラーチェックとエラー処理の方がコード量が多い事も普通
697 : Name_Not - 2015/02/03(火) 12:30:06.64 ID:???.net (+15,-29,-55)
>>696
それは作り方が悪いな。
エラーを戻り値で返すパターンをやるとそうなる。
try-catchで捕まえてエラーをreturn -1とかするようなコードね。

例外を正しく使えばエラー処理のコードは少なくなるし、
JavaScriptの場合、window.onerrorで未知のエラーを
一括して捕まえることも出来る。
698 : Name_Not - 2015/02/03(火) 12:43:52.27 ID:???.net (+7,-29,-46)
>>697
> エラーを戻り値で返すパターンをやるとそうなる。
全てのAPIでエラーコードが違う場合にはそうせざるを得ないしそれで正しい
try-catchで括るのは単に楽してるだけ
699 : Name_Not - 2015/02/03(火) 12:50:37.15 ID:???.net (+41,-28,-101)
>>698
正しくねーよw

そういうのは、エラーコードをラップした
エラーオブジェクトを作ってthrowするもんだ。

そうすれば、エラーメッセージ等は
そのエラーオブジェクトに処理を任せられる。

そして特殊な処理をしたい場合だけcatchすればいい。

> try-catchで括るのは単に楽してるだけ
当たり前だろ。戻り値でエラーを返すやり方では面倒だから
ほぼ全ての言語に例外が搭載されたんだぞ。
楽して対応できるのだから、そっちのほうがいいだろ。
700 : Name_Not - 2015/02/03(火) 13:01:43.77 ID:???.net (+105,+29,-44)
>>699
> そういうのは、エラーコードをラップした
> エラーオブジェクトを作ってthrowするもんだ。
それだったら結局同じことをやっているに過ぎない
try-catchを使えば楽になるなんて迷信だ
←前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 次へ→ / 要望・削除依頼は掲示板へ / 管理情報はtwitterで / JavaScript スレッド一覧へ
スレッド評価: スレッド評価について
みんなの評価 :
タグ : 追加: タグについて ※前スレ・次スレは、スレ番号だけ登録。駄スレにはタグつけず、スレ評価を。荒らしタグにはタグで対抗せず、タグ減点を。

類似してるかもしれないスレッド


トップメニューへ / →のくす牧場書庫について