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

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

    JavaScript覧 / PC版 /
    スレッド評価: スレッド評価について
    みんなの評価 :
    タグ : 追加: タグについて ※前スレ・次スレは、スレ番号だけ登録。駄スレにはタグつけず、スレ評価を。荒らしタグにはタグで対抗せず、タグ減点を。
    ←前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 次へ→ / 要望・削除依頼は掲示板へ / 管理情報はtwitter

    651 = :

    じゃあなんで>>640は循環参照するのに>>646は循環参照しないんですか

    652 = :

    >>651
    >>640は循環参照しません

    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 = :

    >>610じゃなくて>>690

    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を使えば楽になるなんて迷信だ


    ←前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 次へ→ / 要望・削除依頼は掲示板へ / 管理情報はtwitterで / JavaScript一覧へ
    スレッド評価: スレッド評価について
    みんなの評価 :
    タグ : 追加: タグについて ※前スレ・次スレは、スレ番号だけ登録。駄スレにはタグつけず、スレ評価を。荒らしタグにはタグで対抗せず、タグ減点を。

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


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