4

関数this内では使えないようです。setInerval何故ですか?エレガントなソリューションとは何ですか?

<html>
<script>
var something = function(tMessage){
    this.message = tMessage;
};

something.prototype = {
    start : function(counter){
       document.getElementById('result').innerHTML += this.message + "+++<br />";
        var looper = setInterval(
            function(){
                // This is printing "undefined"
                document.getElementById('result').innerHTML += this.message + "<br />";
                if(!counter--)
                    clearInterval(looper);
            },
            20
        );
    }
};


window.onload = function(){
    var e = new something("hi");
    e.start(2);
}
</script>
<body>
<div id="result"></div>
</body>
</html>

編集

答えてくれてありがとう!しかし、引数の送信と設定および追加の変数の違いを誰かが説明できますか?メモリの問題はありますか?

4

4 に答える 4

6

ここでの問題は、関数が呼び出されたときthisにグローバルオブジェクトを参照することです。現在のスコープを保持するために、クロージャを作成できます。

    var looper = setInterval(
        (function(scope){
            return function(){
                // This will no longer be printing "undefined"
                document.getElementById('result').innerHTML += scope.message + "<br />";
                if(!counter--)
                    clearInterval(looper);
            };
         })(this),
        20
    );

手で振ってクロージャを説明しようとする代わりに(私はまだ完全に習得中です)、この優れた答えにあなたを導きます:https ://stackoverflow.com/a/111200/1726343

于 2012-11-17T12:34:46.727 に答える
4

this新しい機能ブロックにいるため、使用できません。私は常にローカル変数を作成しています(もっと良い方法があると確信しています):

var c = this;
setInterval(function(
   c.variable = 1;
), 100);
于 2012-11-17T12:32:46.663 に答える
1

質問には [prototypejs] というタグが付けられていますが、Prototype を使用する回答が 1 つもないため、実際に Prototype ( jsfiddle ) を使用する回答を作成することにしました。

var Something = Class.create({
    initialize: function(tMessage) {
        this.message = tMessage;
    },

    start: function(counter) {
        this.counter = counter;
        $("result").innerHTML += this.message + "+++<br />";
        this.looper = setInterval(this.addMessage.bind(this), 20);
    },

    addMessage: function() {
        $("result").innerHTML += this.message + "<br />";
        if (!this.counter--) {
            clearInterval(this.looper);
        }
    }
});

document.observe("dom:loaded", function() {
    var e = new Something("hi");
    e.start(2);
});
  1. Class.create()を使用して、より洗練されたクラスを作成します。
  2. の代わりに$()を使用しdocument.getElementById()ます。
  3. 代わりにdocument.observe("dom:loaded")を使用してくださいwindow.onload
  4. bind(this)を使用して、関数をコンテキストにバインドします。

問題の重要なポイントは、関数の実行コンテキストにあります。どこで を使用thisしても、現在の実行コンテキストを指すだけです。を呼び出すとsomeObject.someFunction()someFunction()は のコンテキストで実行されsomeObject、のthis内部はsomeFunction()を指しsomeObjectます。

しかし、代入を行うことはできます。そうすればsomeOtherObject.someFunction = someObject.someFunction、insomeOtherObject.someFunction() thisは を指しsomeOtherObjectます。

また、 で行ったように、関数への参照を別の関数に渡すこともできます。setInterval()実行コンテキストは によって定義されますsetInterval()(実際にはグローバル コンテキスト、つまり になりますthis===window)。

実行コンテキストを関数にバインドするには (コンテキストを事前定義し、呼び出し側のコンテキストをオーバーライドします)、.bind()メソッドを使用する必要があります。これは、実行時のコンテキストに関係なく、目的のコンテキストで元の関数を呼び出す新しい関数を返します。

于 2012-11-20T08:10:26.447 に答える
0

追加

var self = this;

setInterval を呼び出す直前に、 set*interval で定義された関数に this の代わりに self を使用します

于 2012-11-17T12:43:32.357 に答える