元スレ+ JavaScript の質問用スレッド vol.122 +
JavaScript覧 / PC版 /みんなの評価 :
651 = :
じゃあなんで>>640は循環参照するのに>>646は循環参照しないんですか
652 = :
653 = :
>>639
>>553を読めばわかる
> としとけばいいんでない
普通はやる必要がないこと。
removeEventListenerをするためには、名前を付けないといけない。
せっかくクロージャーを使って無名関数で
イベントハンドラを記述できるというのに、それは
newしたものを必ずdeleteしなければならない言語の
ようなもの。面倒くさい
> 一度しか実行されないハンドラは少数に限られるだろうから
それが昔のIEはページを移動してもメモリは解放されなかった。
だからどんどんブラウザが重くなっていった。
jQueryを使った場合は、クロージャーを使って本来あるべき姿のように
簡単に記述できていながら、メモリリークもしないようになっていた。
654 = :
>>641
> クロージャを少なくする設計には賛成だが、循環参照は関係ない
クロージャを少なくする設計なんて考えていたら、
全然問題がないEcmaScriptのmapやforEach、
underscoreやlodashの関数まで
クロージャー使わないほうがいいって勘違いするぞ。
問題は生存期間が長いイベントハンドラでクロージャーを使うと、
それが呼び出されたのと同じスコープの変数も使わないものであっても
生き残ってしまうっていうのが問題だろ。
だから逆にそのスコープ内の変数の方をなくしてもいい。
655 = :
>>654
要するに循環参照しない
656 = :
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 = :
>>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 = :
>>657
バッチリです。やっぱりjQuery便利やね
659 = :
>>655
循環参照はあまり関係ない
660 = :
この話を聞くと、Javaのクロージャーもどき(ラムダ)の
仕様は正解だったかもしれんな。
JavaScriptやいろんな言語のクロージャーはクロージャーの中から
aが見えてしまう。つまりイベントハンドラが生きてる間中、
イベントハンドラからaを参照しなくても、aが生き残ってしまう。
function foo() {
var a = [巨大な配列];
window.addEventHandler('load', function() {
// ここからaが見える
});
}
でも、javaのラムダは、aが見えない。
それがラムダはクロージャーではないと言われる理由なんだが、
ラムダであればクロージャーを使った場合のこの問題が無くなる。
クロージャーはあってもいいと思うんだけど
クロージャーとラムダの両方がほしい。そして必要ないならば
ラムダの方を使うべきだろう。
661 = :
>>659
循環参照ではなくて、ハンドラに使ったクロージャーは
生存期間が長いっていうのが問題だよね。
クロージャーの生存期間が短い場合は
クロージャーを使っても何の問題もない。
662 = :
>>661
そうだね。
(DOMとJavaScriptの)循環参照はメモリリークを招くという
古いIEのバグに関連する話で、
それを除けば循環参照してもよい。
ただ循環参照とハンドラの生存期間が長い問題は別の話で
ハンドラにクロージャーを使用すると、クロージャーから見える
そのスコープにある変数すべてがメモリ内に残ってしまう。
これはIEの循環参照のバグとは別の話。
663 = :
>>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 = :
>>659
>>555で「↓なぜこれが循環参照になるのかというと」と明言している意図は?
初めから「循環参照は関係ない」と指摘しているのにあなたは枝葉にばかり拘っている
665 = :
>>664
循環参照にこだわるから、循環参照することは悪いのかって話になって
本当の問題が見えてこなくなる。
例えば、forEachでクロージャーを使っても循環参照する。だけどこれは問題ならない。
なぜならforEachのクロージャーの生存期間は凄く短いから。
本当の問題は、ハンドラであれば一般的にクロージャーの生存期間が長いことにある。
両方とも循環参照しているのに、一方は問題なくても一方は問題がある。
その理由は循環参照ではなくて、生存期間であるということに気づかないといけない。
それさえわかっていれば、クロージャーを使ってもいいことが理解できるはず。
本当の問題を理解せずに、わかりやすいからといってクロージャーは使ったらだめという
決まりを作ると、ルールだけが生き残ることになる。
666 = :
>>553
これremoveEventせずにDOMオブジェクトが消滅したらどうなるの?
ハンドラは開放されず永久に残リ続ける?
667 = :
>>665
そんなことは理解している
繰り返すが、>>555で「↓なぜこれが循環参照になるのかというと」と明言している意図は?
668 = :
>>666
> これremoveEventせずにDOMオブジェクトが消滅したらどうなるの?
DOMを消す時に、jQuery内部のcleanDataが呼ばれる。
cleanDataではDOMに関連づいたデータを全て消去する。
669 = :
>>647
> 繰り返すが、>>555で「↓なぜこれが循環参照になるのかというと」と明言している意図は?
古いIEでメモリリークする原因が、DOMとJavaScriptの間で
循環参照しているからだろ。「"DOMとJavaScriptの間で"循環参照してる」という
説明なしに、古いIEでメモリリークする理由を説明することは出来ない。
ここまでで一区切り。以下次の話として、
今の時代は古いIEは消えてしまったと考えていいものとする。
古いIEは消えてしまったのだから、循環参照しても問題ないよね?
そうは問屋が卸さない。
メモリリークの問題はなくなったが、
生存期間による不要なメモリ使用の問題は残っている。
これが今も起きてる注意すべき問題の話。
670 = :
そーゆーのってどうやってチェックするの?
タスクマネージャーを随時みるの?
671 = :
>>670
今はブラウザの開発者ツールに内蔵されてるよ。
昔は昔でそういうのを検出するプラグインがあった。
672 = :
>>668
MutationEventのようなもので監視してるわけではないのかな?
jQuery以外のAPIを叩いたり
ブラウザが勝手にDOMオブジェクトを消滅させた時はリークする?
673 = :
ダミーのデータを使ってわざと数十MB単位でメモリを使うように
すればタスクマネージャーでもわかると思う
674 = :
>>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 = :
>>669
> 古いIEでメモリリークする原因が、DOMとJavaScriptの間で
> 循環参照しているからだろ。「
>>641で「巨大な配列がDOMでなければ循環参照しない」と指摘したはずだが、具体的に循環参照する「DOMオブジェクト」と「JavaScriptオブジェクト」は何だ?
function foo() {
var a = [巨大な配列];
window.addEventHandler('load', function() {
alert(a.length);
alert(foo.name);
});
}
# 以下、戯言。
# 同じ内容を4回説明してようやく本題「循環参照しない」に入れたわけだが、何を答えてよいかわからない程の難問だったのかね…。
676 = :
>>675
それでお前が言いたいことは何なんだよ?w
678 = :
>>675
addEventHandlerって何だ、と思ったら>>555が出典だからか
普段から素のJavaScriptコードを書いているなら間違えるわけがないんだが
679 = :
>>678
すまんすまん。普段は書いてないよ。
jQueryの方を使うほうが楽なのでね。
681 = :
>>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);
}
これは循環参照する。
684 = :
>>681
> お、気づいたかw
あなたが気が付いてないだけで>>641から同じ指摘を何度もしている
対してあなたは何を勘違いしたのか、無関係な返答を繰り返すばかり
あなたは気が付くのが遅すぎる
685 = :
>>682
「対象IEのバージョン」と「MSDNのソースURL」を教えてください
グローバルオブジェクト(DOM)を含む循環参照でもメモリリークするなら回避手段はないと思いますが、当時はどうしていたのでしょう?
686 = :
>>683
関数1つ作ったらグローバルスコープの参照カウンタは回るのでは?
関数スコープの外はすべてクロージャなんだから
687 = :
>>660
今のブラウザなら大丈夫なはず
自分で確かめてないからアレだけど、検証結果がこのスレ(の過去スレ)にも貼られていた
ただしハンドラ内でeval()を使ったりすると、そこを通るまでaが参照されるか不明なので
aは残ってしまうだろうね
688 = :
>>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 = :
ローカル変数はスコープチェーン上で始めに一番近い関数スコープから参照するのでグローバルスコープの参照は発生しえないね
690 = :
a[1] == 1
このときaが配列じゃなかったら
Uncaught TypeError: Cannot read property '1' of null
ってエラーになりますが
a != null && a[1] == 1
って書くのが正解ですか?
691 = :
>>610
エラーになるべきなら、エラーになっていいだろ?
それともaがnullになることが有るのですか?
そしてaがnullだったら、
aには何も入れないという"仕様"ですか?
692 = :
693 = :
たとえばさjsonpで取得した時ですよ
サーバから正常にデータを取得出来た時にaは配列になるけど
ただしいデータが送られて来なかった場合はaはnullになります
694 = :
>>693
正しいデータが送られてこなかった場合は、
エラーなんだから、エラーでいいじゃん?
なんで正しいデータが送られてこない時にまで
そのエラーを握りつぶして、無理やり動かすようなことをするのさ?
695 = :
正しいデータが送られてこなかったら
エラーが発生しましたって表示させるか、
ログなどに表示して、そこに来る前に処理を打ち切るんだよ
696 = :
本気でコード書いたらエラーチェックとエラー処理の方がコード量が多い事も普通
697 = :
>>696
それは作り方が悪いな。
エラーを戻り値で返すパターンをやるとそうなる。
try-catchで捕まえてエラーをreturn -1とかするようなコードね。
例外を正しく使えばエラー処理のコードは少なくなるし、
JavaScriptの場合、window.onerrorで未知のエラーを
一括して捕まえることも出来る。
698 = :
>>697
> エラーを戻り値で返すパターンをやるとそうなる。
全てのAPIでエラーコードが違う場合にはそうせざるを得ないしそれで正しい
try-catchで括るのは単に楽してるだけ
699 = :
>>698
正しくねーよw
そういうのは、エラーコードをラップした
エラーオブジェクトを作ってthrowするもんだ。
そうすれば、エラーメッセージ等は
そのエラーオブジェクトに処理を任せられる。
そして特殊な処理をしたい場合だけcatchすればいい。
> try-catchで括るのは単に楽してるだけ
当たり前だろ。戻り値でエラーを返すやり方では面倒だから
ほぼ全ての言語に例外が搭載されたんだぞ。
楽して対応できるのだから、そっちのほうがいいだろ。
700 = :
>>699
> そういうのは、エラーコードをラップした
> エラーオブジェクトを作ってthrowするもんだ。
それだったら結局同じことをやっているに過ぎない
try-catchを使えば楽になるなんて迷信だ
類似してるかもしれないスレッド
- + JavaScript の質問用スレッド vol.122 + (116) - [100%] - 2018/5/2 18:30
- + JavaScript の質問用スレッド vol.125 + (1001) - [97%] - 2015/10/7 17:45
- + JavaScript の質問用スレッド vol.123 + (966) - [97%] - 2020/10/20 2:30
- + JavaScript の質問用スレッド vol.120 + (1002) - [97%] - 2014/11/8 1:15
- + JavaScript の質問用スレッド vol.124 + (1001) - [97%] - 2015/7/16 1:30
- + JavaScript の質問用スレッド vol.121 + (1001) - [97%] - 2022/11/29 16:30
- + JavaScript の質問用スレッド vol.132 + (1001) - [97%] - 2018/4/19 11:00
- + JavaScript の質問用スレッド vol.142 + (984) - [97%] - 2020/8/27 19:15
- + JavaScript の質問用スレッド vol.112 + (1001) - [97%] - 2013/11/27 16:46
- + JavaScript の質問用スレッド vol.121 + (1001) - [97%] - 2015/1/1 18:30
- + JavaScript の質問用スレッド vol.129 + (981) - [97%] - 2016/5/5 8:16
- + JavaScript の質問用スレッド vol.129 + (926) - [97%] - 2017/7/27 13:45
- + JavaScript の質問用スレッド vol.128 + (1001) - [97%] - 2016/2/26 6:45
- + JavaScript の質問用スレッド vol.123 + (1002) - [97%] - 2015/4/27 23:30
- + JavaScript の質問用スレッド vol.127 + (1001) - [97%] - 2016/2/4 0:15
- + JavaScript の質問用スレッド vol.127 + (160) - [97%] - 2021/7/16 9:30
- + JavaScript の質問用スレッド vol.142 + (926) - [97%] - 2019/12/23 13:15
トップメニューへ / →のくす牧場書庫について