为什么我从 JSLint 获得从事件调用的函数的 "is out of scope"?

Why am I getting "is out of scope" from JSLint for a function called from an event?

我需要重新初始化来自两个不同事件(一个 html select 变化和一个复选框变化)的一些 html 元素的状态,所以我创建了一个我放置的函数在 "ready" 函数之外执行此操作,并从两个事件中调用它。

但是,JSLint 标记了对它的调用:

$('#unitsselect').change(function() {
    unitSelected = true;

    reinitializeRecipientsAndGenerateVals();
    . . .

...作为 "out of scope";具体来说,它告诉我,

'reinitializeRecipientsAndGenerateVals' is out of scope.

并指出该行是有问题的行。

reinitializeRecipientsAndGenerateVals() 确实在 change 事件处理程序之外,也在 "ready" 函数之外。我将它放在就绪函数中以查看是否是问题所在,但我仍然从 JSLint 那里收到警告。

我怎样才能重用这个函数,这样我就不必在两个更改事件处理程序中移动它?

注意:This 有一个 "used out of scope" 部分,但没有 "is out of scope"

根据 this,所有版本的 JSLint 都使用“{a} 在绑定上下文之外使用”

更新

即使我将函数右移 更改事件处理程序中,JSLint 也会以同样的方式抱怨。

UDPATE 2

对于 Travis,这是整个辣酱玉米饼馅:

$(document).ready(function() {

    var unitSelected = false;
    var checkboxSelected = false;

    // When unit is selected, populate the data range value elements; if checkbox selected,
    // also populate email recipients and generate vals (specific day or based on a pattern)
    $('#unitsselect').change(function() {
        unitSelected = true;

        reinitializeRecipientsAndGenerateVals();

        var unitval = $('#unitsselect').val();
        // This is admittedly kludgy - copying the same ajax call multiple times, changing only
        // the report number; but a forloop attempt failed because of the asynchronous nature of
        // it all; for some reason, populatedatarangeprams() was called only once, and with a
        // rptval of 5 (when it "should have been" 1..4 instead).
        var model = JSON.stringify({ unit: unitval, report: 1 });
        $.ajax({
            type: 'GET',
            url: '@Url.Action("GetUnitDataRangeParamsVals", "UnitReportDataRangeParams")',
            data: { unit: unitval, report: 1 },
            contentType: 'application/json',
            cache: false,
            success: function(returneddata) {
                populatedatarangeprams(1, returneddata);
            },
            error: function() {
                alert('error - returneddata.error.stringify');
            }
        });

        model = JSON.stringify({ unit: unitval, report: 2 });
        $.ajax({
            type: 'GET',
            url: '@Url.Action("GetUnitDataRangeParamsVals", "UnitReportDataRangeParams")',
            data: { unit: unitval, report: 2 },
            contentType: 'application/json',
            cache: false,
            success: function(returneddata) {
                populatedatarangeprams(2, returneddata);
            },
            error: function() {
                alert('error - returneddata.error.stringify');
            }
        });

        model = JSON.stringify({ unit: unitval, report: 3 });
        $.ajax({
            type: 'GET',
            url: '@Url.Action("GetUnitDataRangeParamsVals", "UnitReportDataRangeParams")',
            data: { unit: unitval, report: 3 },
            contentType: 'application/json',
            cache: false,
            success: function(returneddata) {
                populatedatarangeprams(3, returneddata);
            },
            error: function() {
                alert('error - returneddata.error.stringify');
            }
        });

        model = JSON.stringify({ unit: unitval, report: 4 });
        $.ajax({
            type: 'GET',
            url: '@Url.Action("GetUnitDataRangeParamsVals", "UnitReportDataRangeParams")',
            data: { unit: unitval, report: 4 },
            contentType: 'application/json',
            cache: false,
            success: function(returneddata) {
                populatedatarangeprams(4, returneddata);
            },
            error: function() {
                alert('error - returneddata.error.stringify');
            }
        });

        if (!checkboxSelected) {
            return;
        }

        // from 
        rptval = $('[id^=ckbx_]').filter(':checked').val();
        setEmailAndGenerateValsForUnitReportPair(unitval, rptval);
    }); // $('#unitsselect').change(function ()

    // Checkbox selection has changed; if Unit has been selected, populate the email and generate vals
    $(".ckbx").change(function() {
        if (!this.checked) {
            checkboxSelected = false;
            reinitializeRecipientsAndGenerateVals();
            return;
        }

        checkboxSelected = true;
        // this unchecks all other checkboxes (from 
        $('.ckbx').not(this).prop('checked', false);
        reinitializeRecipientsAndGenerateVals();

        // If no unit is selected, vals can not be set, so exit now
        if (!unitSelected) {
            return;
        }

        var unitval = $('#unitsselect').val();
        var rptval = $(this).val();
        setEmailAndGenerateValsForUnitReportPair(unitval, rptval);
    }); // $(".ckbx").change(function ()

}); // "ready" function

    function setEmailAndGenerateValsForUnitReportPair(unitval, rptval) {
        var model = JSON.stringify({ unit: unitval, report: rptval });
        $.ajax({
            type: 'GET',
            url: '@Url.Action("GetUnitReportPairEmailAddresses", "UnitReportPair")',
            data: { unit: unitval, report: rptval },
            contentType: 'application/json', //<= this is paired with stringify above; if comment out one, comment out both
            cache: false,
            success: function(returneddata) {
                populateemails(returneddata);
            },
            error: function() {
                alert(returneddata.error.stringify);
            }
        });

        // The above AJAX call retrieved email addr vals; the next one is for the "Generate and Email Report" section of the page
        $.ajax({
            type: 'GET',
            url: '@Url.Action("GetUnitReportPairGenerateVals", "UnitReportPairGenerateVals")',
            data: { unit: unitval, report: rptval },
            contentType: 'application/json',
            cache: false,
            success: function(returneddata) {
                populategeneratevals(returneddata);
            },
            error: function() {
                alert(returneddata.error.stringify);
            }
        });
    }

    //Adapted from Jakes's answer here: 
    function isCheckedById(id) {
        var checked = $("input[id=" + id + "]:checked").length;
        return (checked != 0);
    }

    function populateemails(trampdata) {
        // first, clear them all
        $("#email1").val('');
        $("#email2").val('');
        $("#email3").val('');
        // Now set those for which there are values
        if (trampdata.UnitReportPairEmailVals.length > 0) {
            $("#email1").val(trampdata.UnitReportPairEmailVals[0]);
        }
        if (trampdata.UnitReportPairEmailVals.length > 1) {
            $("#email2").val(trampdata.UnitReportPairEmailVals[1]);
        }
        if (trampdata.UnitReportPairEmailVals.length > 2) {
            $("#email3").val(trampdata.UnitReportPairEmailVals[2]);
        }
    }

    function populategeneratevals(generateddata) {
        // first, clear them all, if they had been set to something else
        $("#dayofmonthselect").val('1st');
        $("#ordinalselect").val('First');
        $("#dayofweekselect").val('Monday');
        $("#weekormonthselect").val('Month');

        // Now set those for which there are values
        var domOrdinalified = ordinalify(generateddata.generatevals.DayOfMonth);
        $("#dayofmonthselect").val(domOrdinalified);
        $("#ordinalselect").val(generateddata.generatevals.PatternOrdinal);
        $("#dayofweekselect").val(generateddata.generatevals.PatternDOW);
        $("#weekormonthselect").val(generateddata.generatevals.PatternInterval);

        // Now set the correct radio button
        if ($("#dayofmonthselect").val() === 0) {
            $("#groupRptGenerationAndSendingByDayOfMonth").prop("checked", true);
        } else {
            $("#groupRptGenerationAndSendingBasedOnAPattern").prop("checked", true);
        }
    }

    function ordinalify(domint) {
        if (domint === 1 || domint === 21 || domint === 31) {
            return domint + 'st';
        }
        if (domint === 2 || domint === 22) {
            return domint + 'nd';
        }
        if (domint === 3 || domint === 23) {
            return domint + 'rd';
        }
        return domint + 'th';
    }

    function populatedatarangeprams(rptval, returneddata) {
        if (rptval === 1) {
            // Produce Usage
            $("#produsagefrom").val(returneddata.datarangeparams.TimeUnitsFrom);
            $("#produsageto").val(returneddata.datarangeparams.TimeUnitsTo);
        } else if (rptval === 2) {
            // Delivery Performance
            $("#delperffrom").val(returneddata.datarangeparams.TimeUnitsFrom);
            $("#delperfto").val(returneddata.datarangeparams.TimeUnitsTo);
        } else if (rptval === 3) {
            // Price Compliance
            $("#pricecompliancefrom").val(returneddata.datarangeparams.TimeUnitsFrom);
            $("#pricecomplianceto").val(returneddata.datarangeparams.TimeUnitsTo);
        } else if (rptval === 4) {
            // Fill Rate
            $("#fillratefrom").val(returneddata.datarangeparams.TimeUnitsFrom);
            $("#fillrateto").val(returneddata.datarangeparams.TimeUnitsTo);
        }
        // TODO: Add 5 if/when Contract vs Market is added
    }

    function reinitializeRecipientsAndGenerateVals() {
        $("#email1").val('');
        $("#email2").val('');
        $("#email3").val('');

        $("#dayofmonthselect").val('1st');
        $("#ordinalselect").val('First');
        $("#dayofweekselect").val('Monday');
        $("#weekormonthselect").val('Month');
    }

您可以使用函数参数 reinit,稍后将其绑定到 reinitializeRecipientsAndGenerateVals(您要重用的函数)。

var onChange = (function(reinit) {
   unitSelected = true;
   reinit();
   ...
}).bind(null, reinitializeRecipientsAndGenerateVals)

$('#unitsselect').change(onChange)

好的,我已经找到了:

foo(); // <- function call

function foo() { // <- function declaration
}

"Declare function before calling it!" 或 "Do not rely on hoisting!" 似乎是一种晦涩的表达方式。

您可以通过将函数声明移到顶部来修复它。