1

如下所示,我制作了一个简单的高分数组,将其保存到本地存储并添加到用户提示中。

作为一个独立的文件,它工作得很好。或者至少看起来是这样。

但是,当我尝试将其集成到更大的应用程序中时,我的全局变量 allScores 似乎存在范围问题。数组的长度保持在 0。我检查了是否有任何变量重复,但我没有。

我一直在尝试阅读有关函数提升和范围的信息。我不确定为什么下面的代码作为一个独立文件工作,但是当我将它集成到我更大的应用程序中时,我遇到了范围问题。

我应该如何以不同的方式做到这一点?由于我是 JavaScript 新手,因此我的最佳实践很可能会被取消。感谢您的指导。谢谢。

var allScores = [];

function saveScore() {

if (allScores.length === 0) {
    allScores[0]= prompt('enter score', '');
    localStorage ['allScores'] = JSON.stringify(allScores);
}

else if (allScores.length < 3) {
    var storedScores = JSON.parse(localStorage ['allScores']);
    storedScores = allScores;
    var injectScore = prompt('enter score', '');
    allScores.push(injectScore);
    allScores.sort(function(a, b) {return b-a});
    localStorage ['allScores'] = JSON.stringify(allScores);
}

else {
    var storedScores = JSON.parse(localStorage ['allScores']);
    storedScores = allScores;
    var injectScore = prompt('enter score', '');
    allScores.pop();
    allScores.push(injectScore);
    allScores.sort(function(a, b) {return b-a});
    localStorage ['allScores'] = JSON.stringify(allScores);
}
document.getElementById('readScores').innerHTML = allScores;
}**
4

3 回答 3

1

你考虑过 JS 闭包吗?这里有一些东西给你一个想法..

var scoreboard = (function () {
    var _privateVar = "some value"; //this is never exposed globally
    var _allScores = [];

    return {
        getAllScores: function() { //public
            return _allScores;
        },
        saveScore: function(value) { //public
            _allScores.push(value);
        }
    };
})();

alert(scoreboard.getAllScores().length); //0
scoreboard.saveScore(1);
alert(scoreboard.getAllScores().length); //1
alert(scoreboard._privateVar); //undefined
alert(scoreboard._allScores); //undefined

这样你的变量和函数就不会暴露给 window 对象,你也不需要担心重复或作用域。唯一必须唯一的变量是闭包函数的名称(scoreboard在本例中)。

于 2013-01-16T03:52:59.700 回答
1

由于您在问题中提到了最佳实践,因此我已经重构了您的代码,以显示一些可能对您和其他人将来有所帮助的实践。下面将列出此重构中使用的概念。

var saveScore = (function () { /* Begin IIFE */
    /*
    The variables here are scoped to this function only.
    They are essentially private properties.
    */
    var MAX_ENTRIES = 3;

    /*
    Move the sorting function out of the scope of saveScore,
    since it does not need any of the variables inside,
    and possibly prevent a closure from being created every time
    that saveScore is executed, depending upon your interpreter.
    */
    function sorter(a, b) {
        return b - a;
    }

    /*
    As far as your example code shows, you don't appear to need the
    allScores variable around all the time, since you persist it
    to localStorage, so we have this loadScore function which
    pulls it from storage or returns a blank array.
    */
    function getScores() {
        var scores = localStorage.getItem('scores');
        return scores ? JSON.parse(scores) : [];
        /*
        Please note that JSON.parse *could* throw if "scores" is invalid JSON.
        This should only happen if a user alters their localStorage.
        */
    }

    function saveScore(score) {
        /* Implicitly load the scores from localStorage, if available. */
        var scores = getScores();

        /*
        Coerce the score into a number, if it isn't one already.
        There are a few ways of doing this, among them, Number(),
        parseInt(), and parseFloat(), each with their own behaviors.

        Using Number() will return NaN if the score does not explicitly
        conform to a textually-represented numeral.
        I.e., "300pt" is invalid.

        You could use parseInt(score, 10) to accept patterns
        such as "300pt" but not anything with
        leading non-numeric characters.
        */
        score = Number(score);

        /* If the score did not conform to specifications ... */
        if (isNaN(score)) {
            /*
            You could throw an error here or return false to indicate
            invalid input, depending on how critical the error may be
            and how it will be handled by the rest of the program.

            If this function will accept user input,
            it would be best to return a true or false value,
            but if a non-numeric value is a big problem in your
            program, an exception may be more appropriate.
            */

            // throw new Error('Score input was not a number.');
            // return false;
        }

        scores.push(score);
        scores.sort(sorter);

        /*
        From your code, it looks like you don't want more than 3 scores
        recorded, so we simplify the conditional here and move
        "magic numbers" to the header of the IIFE.
        */
        if (scores.length >= MAX_ENTRIES) {
            scores.length = MAX_ENTRIES;
        }
        /* Limiting an array is as simple as decreasing its length. */

        /* Save the scores at the end. */
        localStorage.setItem('scores', JSON.stringify(scores));

        /* Return true here, if you are using that style of error detection. */
        // return true;
    }

    /* Provide this inner function to the outer scope. */
    return saveScore;

}()); /* End IIFE */

/* Usage */
saveScore(prompt('Enter score.', ''));

如您所见,将您的分数处理逻辑封装在此函数上下文中,几乎没有任何东西可以在不使用接口的情况下篡改内部。从理论上讲,您的saveScore函数可以被其他代码取代,但IIFE's 上下文的内部仅对那些有权访问的代码是可变的。虽然标准化的 ECMAScript中还没有常量, 这种模块模式方法提供了一个不错的解决方案,结果可预测。

于 2013-01-16T04:50:55.650 回答
0

在无法访问您的环境的情况下,您可以做的最好的事情是使用 firefox 开发工具(或获取 firebug)在您的saveScore函数中放置一个断点。您可以逐行逐行检查值,甚至可以在控制台窗口 (REPL) 中评估当前范围内的表达式。

https://developer.mozilla.org/en-US/docs/Tools/Debugger - 使用 Firefox

http://getfirebug.com/javascript - 带有 firebug(一个 firefox 插件)

如果你在做网络开发,这些都是无价的资源,所以花一些时间来学习如何使用它们。(它们会为你节省更多的时间!)

于 2013-01-16T03:19:42.447 回答