不需要的Javascript效果:原型在实例之间共享闭包

不需要的Javascript效果:原型在实例之间共享闭包,javascript,closures,prototype,Javascript,Closures,Prototype,我正在制作一个计时关卡的游戏。级别为2分钟长,右上角显示倒计时计时器。马里奥风格 跟踪已用时间的一种方法是将我的级别对象作为成员变量 Level.init = function(){ this.elapsed = 0; //member variable! return this; }; Level.update = function(){ this.countdown(); }; Level.countdown = function(){ this.ela

我正在制作一个计时关卡的游戏。级别为2分钟长,右上角显示倒计时计时器。马里奥风格

跟踪已用时间的一种方法是将我的
级别
对象作为成员变量

Level.init = function(){
    this.elapsed = 0;  //member variable!
    return this;
};

Level.update = function(){
    this.countdown();
};

Level.countdown = function(){
    this.elapsed += 1;
    var remaining = (GAME_LENGTH*60) - (this.elapsed/TICKS);
    var minutes = Math.floor(remaining/60);
    var seconds = Math.floor(remaining%60);
    this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       

    if (this.elapsed/TICKS >= GAME_LENGTH*60) {
        this.level_end();
    }
};
当游戏引擎需要一个新的关卡时,它会这样创建一个关卡:

NewLevel = Object.create(Level).init();
然而,我认为使用闭包可能很好<代码>经过时间仅由
倒计时
函数使用,因此它不需要是
级别
的成员变量<代码>级别不需要知道
已用时间
存在

//member variable this.elapsed has been removed
Level.init = function(){
    return this;
};

Level.update = function(){
    this.countdown();
};

//a closure is used to keep track of elapsed time
Level.countdown = (function(){
    var elapsed = 0;        
    return function() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       

        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    };
})();
但现在我有一个不同的问题。创建的
级别
的所有副本共享该
倒计时
结束,因为它位于原型链中。当用户提前退出该级别,然后开始一个新的级别(删除旧的
级别
对象,实例化一个新的
级别
对象),闭包中的
已用
变量不会重置

换言之,用户在还剩30秒时提前退出该级别。然后用户再次启动关卡,但现在,倒计时计时器显示的不是整整2分钟,而是30秒

有没有一种优雅的方法可以解决这个问题,并且仍然使用闭包?或者我必须恢复到以前的解决方案,忘记闭包,并将
appeased
作为成员变量

有没有一种优雅的方法可以解决这个问题,并且仍然使用闭包?或者我必须恢复到我以前的解决方案,忘记闭包,并使其成为一个成员变量

它必须是具体的实例;这并不意味着它必须是对象上的属性。您可以从
init
方法中创建闭包:

//member variable this.elapsed has been removed
Level.init = function(){
    //a closure is used to keep track of elapsed time
    this.countdown = createCountdownMethod();
    return this;
};

Level.update = function(){
    this.countdown();
};

function createCountdownMethod(){
    var elapsed = 0;        
    return function() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       

        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    };
}
或者这可能更容易阅读:

//member variable this.elapsed has been removed
Level.init = function(){
    var elapsed = 0;        

    //a closure is used to keep track of elapsed time
    Level.countdown = countdown;
    return this;

    function countdown() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       

        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    }
};

Level.update = function(){
    this.countdown();
};
有没有一种优雅的方法可以解决这个问题,并且仍然使用闭包?或者我必须恢复到我以前的解决方案,忘记闭包,并使其成为一个成员变量

它必须是具体的实例;这并不意味着它必须是对象上的属性。您可以从
init
方法中创建闭包:

//member variable this.elapsed has been removed
Level.init = function(){
    //a closure is used to keep track of elapsed time
    this.countdown = createCountdownMethod();
    return this;
};

Level.update = function(){
    this.countdown();
};

function createCountdownMethod(){
    var elapsed = 0;        
    return function() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       

        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    };
}
或者这可能更容易阅读:

//member variable this.elapsed has been removed
Level.init = function(){
    var elapsed = 0;        

    //a closure is used to keep track of elapsed time
    Level.countdown = countdown;
    return this;

    function countdown() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       

        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    }
};

Level.update = function(){
    this.countdown();
};
有没有一种优雅的方法可以解决这个问题,并且仍然使用闭包?或者我必须恢复到我以前的解决方案,忘记闭包,并使其成为一个成员变量

它必须是具体的实例;这并不意味着它必须是对象上的属性。您可以从
init
方法中创建闭包:

//member variable this.elapsed has been removed
Level.init = function(){
    //a closure is used to keep track of elapsed time
    this.countdown = createCountdownMethod();
    return this;
};

Level.update = function(){
    this.countdown();
};

function createCountdownMethod(){
    var elapsed = 0;        
    return function() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       

        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    };
}
或者这可能更容易阅读:

//member variable this.elapsed has been removed
Level.init = function(){
    var elapsed = 0;        

    //a closure is used to keep track of elapsed time
    Level.countdown = countdown;
    return this;

    function countdown() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       

        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    }
};

Level.update = function(){
    this.countdown();
};
有没有一种优雅的方法可以解决这个问题,并且仍然使用闭包?或者我必须恢复到我以前的解决方案,忘记闭包,并使其成为一个成员变量

它必须是具体的实例;这并不意味着它必须是对象上的属性。您可以从
init
方法中创建闭包:

//member variable this.elapsed has been removed
Level.init = function(){
    //a closure is used to keep track of elapsed time
    this.countdown = createCountdownMethod();
    return this;
};

Level.update = function(){
    this.countdown();
};

function createCountdownMethod(){
    var elapsed = 0;        
    return function() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       

        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    };
}
或者这可能更容易阅读:

//member variable this.elapsed has been removed
Level.init = function(){
    var elapsed = 0;        

    //a closure is used to keep track of elapsed time
    Level.countdown = countdown;
    return this;

    function countdown() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       

        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    }
};

Level.update = function(){
    this.countdown();
};

如果希望将
已用时间
完全私有于
级别
实例,可以将
倒计时
的定义移动到
初始化
。这看起来像:

//member variable this.elapsed has been removed
Level.init = function(){
    var elapsed = 0; // elapsed local to init
    this.countdown = function() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       
        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    };
    return this;
};

Level.update = function(){
    this.countdown();
};

在每次不创建新变量的情况下,不可能对每个实例使用变量(如
appeased
)的闭包。

如果希望将
appeased
完全私有于
级别的
实例,可以将
倒计时的定义移动到
init
。这看起来像:

//member variable this.elapsed has been removed
Level.init = function(){
    var elapsed = 0; // elapsed local to init
    this.countdown = function() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       
        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    };
    return this;
};

Level.update = function(){
    this.countdown();
};

在每次不创建新变量的情况下,不可能对每个实例使用变量(如
appeased
)的闭包。

如果希望将
appeased
完全私有于
级别的
实例,可以将
倒计时的定义移动到
init
。这看起来像:

//member variable this.elapsed has been removed
Level.init = function(){
    var elapsed = 0; // elapsed local to init
    this.countdown = function() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       
        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    };
    return this;
};

Level.update = function(){
    this.countdown();
};

在每次不创建新变量的情况下,不可能对每个实例使用变量(如
appeased
)的闭包。

如果希望将
appeased
完全私有于
级别的
实例,可以将
倒计时的定义移动到
init
。这看起来像:

//member variable this.elapsed has been removed
Level.init = function(){
    var elapsed = 0; // elapsed local to init
    this.countdown = function() {
        elapsed += 1;
        var remaining = (GAME_LENGTH*60) - (elapsed/TICKS);
        var minutes = Math.floor(remaining/60);
        var seconds = Math.floor(remaining%60);
        this.countdown.html(minutes + ":" + ("0"+seconds).slice(-2));       
        if (elapsed/TICKS >= GAME_LENGTH*60) {
            elapsed = 0;
            this.end_level();
        }
    };
    return this;
};

Level.update = function(){
    this.countdown();
};
在每次不创建新变量的情况下,不可能对每个实例使用变量(如
appead
)的闭包