【问题标题】:Javascript: Object context overwritten?Javascript:对象上下文被覆盖?
【发布时间】:2013-08-29 09:50:22
【问题描述】:

我知道在我的以下 Javascript 代码中存在某种上下文混淆。

谁能解释我为什么会遇到这个问题以及如何解决这个问题?

我有一个名为 Model 的类,它似乎工作得很好。在这个类中有一个名为 update() 的方法。这将对后端执行 AJAX 调用并解析返回的 JSON。这就是事情变得棘手的地方。正确的查询被发送到后端,正确的 JSON 被发回。但是,在解析过程中,两个模型之间存在某种冲突或上下文问题。

我通过另一个名为 View 的对象调用更新函数。这个 View 对象有一个模型列表(模型的实例)。然后视图将调用每个视图的每个更新函数。在解析返回的数据之前,这很有效。

如 cmets 中所述,这是数据对象的示例(手动重新创建,无法弄清楚如何从控制台复制它)。请注意,此对象可能没有索引 0 中的所有条目(例如,在以下情况下,它可能缺少 TLM_NO)。此外,返回的行数(在这种情况下只有 '0' 不同)。更新函数的部分目标是检测到这一点,并在 DOM 的正确部分填充“N/A”以防万一。

{valid: true,
 0: {'TLM_NO': '00000', 'TLM_NAME': 'YYY-14 Tlm Rel 19'}}

在下面的代码中,一切都很好,直到出现注释“/!\ HERE /!\”的那一行。

this.update = function(dbi) {
console.log('Updating model ' + this.name + '.');
var modelObj = this; // This is used to have a reference to 'this' Model while in other contexts.
if (this.columns.length == 0) {
    /* Let's build all the columns */
    $("[id^='" + this.ref + "']").each(function() {
    var colName = $(this).attr('id').split('-')[1];
    if (modelObj.columns.indexOf(colName) == -1) {
        modelObj.columns.push(colName);
    }
    });
}

/* Let's build the bindings. */
var allBindings = {};
for (placeholder in this.bindings) {
    allBindings[placeholder] = this.bindings[placeholder].val();
}

$.post(path + 'inc/fetch.php', {
    dbi : dbi,
    table : this.table,
    columns : btoa(this.columns),
    limit : this.limit,
    offset : this.offset,
    distinct : this.distinct,
    where : btoa(this.where),
    bindings : btoa(JSON.stringify(allBindings))
}, function(data) {
    if (!data.valid) {
    $("#userError>p>span.userMessage").html(data.msg);
    $("#userError").dialog({
        width : 500,
        buttons : {
        'Dismiss' : function() {
            $(this).dialog("close");
        }
        }
    });
    } else {
    /* The data returned by the backend is simply JSON data with the key-value pair. There is one key per row returned. */
    var numRows = 0; // /!\ HERE /!\ Starting here, displaying the data variable will always display the first of two objects.
    for ( var rowID in data) {
        if (rowID == 'valid')
        continue;
        numRows++;
        for (column in data[rowID]) {
        console.log('[' + modelObj.str() + '] setting #' + modelObj.ref + '-' + column + ' to [' + data[rowID][column] + ']');
        var el = $('#' + modelObj.ref + '-' + column);
        var val = data[rowID][column];
        switch (el[0].nodeName) {
        case "SELECT":
            el.html('<option val="' + val + "'>" + val + "</option>");
            break;
        case "TD":
            el.text(val);
            break;
        case "INPUT":
            el.val(val);
            break;
        default:
            console.log('Dont know how to display "' + val + '"!');
        }
        }
    }
    if (numRows < modelObj.columns.length) {
        for ( var cNo in modelObj.columns) {
        var column = modelObj.columns[cNo];
        console.log("col = " + column);
        console.log('data');
        console.log(data);
        console.log('columns');
        console.log(modelObj.columns);
        console.log('[0] of ' + '#' + modelObj.ref)
        var par = $('#' + modelObj.ref).nodeName;
        var el = $('#' + modelObj.ref + '-' + column);
        var val = data[0][column];
        switch (par) {
        case "SELECT":
            el.html('<option val="' + val + "'>" + val + "</option>");
            break;
        case "TABLE":
            var limit = $('#' + modelObj.ref + ">tr").length - 1; // The first line (tr) is the header.
            for ( var missingRow in limit) {
            if (data.hasOwnProperty(missingRow) == 0 || data[missingRow].hasOwnProperty(column) == 0) {
                console.log('[' + modelObj.str() + '] setting #' + modelObj.ref + '-' + column + ' to [N/A]')
                $('#' + modelObj.ref + '-' + column + '-' + missingRow).text('N/A');
            }
            }

            break;
        case "INPUT":
            el.val(val);
            break;
        default:
            console.log('Dont know how to display "' + val + '"!');
        }

        }
    }
    }
}, "json");
};

任何想法都是有帮助的。提前致谢。

【问题讨论】:

  • 如果您提供一个示例数据对象会非常方便。
  • 另外,如果 'for ( var rowID in data)' 用于解析数组,更简单的方法是使用传统的 for(var i=0; i
  • 使用不同的结构会不会更透明,比如:pastebin.com/Bhz9rsVm?我不确定如何帮助您处理代码,因为这需要我没有时间进行更仔细的检查,但是使对象更清晰可能只会有助于缓解问题
  • 注意:您的代码很难阅读,因为不容易查看变量是否已经绑定到范围内,或者是否存在范围问题。虽然起初for (column in data[rowID]) { 看起来column 没有绑定 到函数范围,但第二次看很明显它是,因为它后来用var column = modelObj.columns[cNo]; 定义。 (JavaScript 没有块级作用域,它只是具有函数级作用域,var variableName; 语句写在作用域的哪个位置无关紧要。
  • 为了便于阅读,您应该在相应范围的开头定义变量。例如this.update = function(dbi) { var modelObj = this, allBindings; ..., function(data) { var numRows /*some comment about num Rows*/, rowID /*some comment about rowID */, el, val, cNo, column, par, limit, missingRow; 这样您就可以从一开始就看到哪些变量绑定到该范围。请记住,JavaScript 没有块级范围,这有助于检测和避免此类问题。

标签: javascript json oop


【解决方案1】:

通过在我希望在其中定义它们的范围顶部声明所有变量,并以更结构化的方式重新排列返回的 JSON 数据(参见下面的粘贴),我能够纠正问题。

作为参考,这里是 JSON 数据。

{"items":[{"TLM_NO":"0000000","TLM_NAME":"NSS-14 Tlm Rel 19"}],"valid":true}

这是更新后的update 方法。

this.update = function(dbi) {
var modelObj = this/* This is used to have a reference to 'this' Model while in other contexts. */;
var allBindings = {} /* Used to relate binding to their values */;
console.log('Updating model ' + this.name + '.');
if (this.columns.length == 0) {
    /* Let's build all the columns */
    $("[id^='" + this.ref + "-']").each(function() {
    var colName = $(this).attr('id').split('-')[1];
    if (modelObj.columns.indexOf(colName) == -1) {
        modelObj.columns.push(colName);
    }
    });
}

/* Let's build the bindings. */
for ( var placeholder in this.bindings) {
    allBindings[placeholder] = this.bindings[placeholder].val();
}

$.post(path + 'inc/fetch.php', {
    dbi : dbi,
    table : this.table,
    columns : btoa(this.columns),
    limit : this.limit,
    offset : this.offset,
    distinct : this.distinct,
    where : btoa(this.where),
    bindings : btoa(JSON.stringify(allBindings))
}, function(data) {
    var numRows = 0 /* Used to parse data. */;
    var el /* Will store the element where to set the */;
    var val /* will store the current value returned in JSON. */;
    var par /* will store the parent element of 'el'. */;
    var updateRows = true; /* This is used to count the rows. We only have to count them once. */
    if (!data.valid) {
    $("#userError>p>span.userMessage").html(data.msg);
    $("#userError").dialog({
        width : 500,
        buttons : {
        'Dismiss' : function() {
            $(this).dialog("close");
        }
        }
    });
    return;
    } else {
    /* The data returned by the backend is simply JSON data with the key-value pair. There is one key per row returned. */

    for ( var rowID in data.items) {
        for ( var cur_Column in data.items[rowID]) {
        if (updateRows)
            numRows++;

        console.log('[' + modelObj.str() + '] setting #' + modelObj.ref + '-' + cur_Column + ' to [' + data.items[rowID][cur_Column] + ']');
        el = $('#' + modelObj.ref + '-' + cur_Column);
        val = data.items[rowID][cur_Column];
        switch (el[0].nodeName) {
        case "SELECT":
            el.append('<option value="' + val + '">' + val + "</option>");
            break;
        case "TD":
            el.text(val);
            break;
        case "INPUT":
            el.val(val);
            break;
        default:
            console.log('Dont know how to display "' + val + '"!');
        }
        }
        updateRows = false;
    }

    if (numRows < modelObj.columns.length) {
        for ( var cNo in modelObj.columns) {
        var curColumnCorr = modelObj.columns[cNo];
        par = $('#' + modelObj.ref)[0].nodeName; // TODO add model name to whatever parent there is.
        el = $('#' + modelObj.ref + '-' + curColumnCorr);
        switch (par) {
        case "TABLE":
            for ( var missingRow = 1; missingRow <= modelObj.limit; missingRow++) {
            if (data.items.hasOwnProperty(missingRow) == 0 || data.items[missingRow].hasOwnProperty(curColumnCorr) == 0) {
                console.log('[' + modelObj.str() + '] setting ' + '#' + modelObj.ref + '-' + curColumnCorr + '-' + missingRow + ' to [N/A]');
                $('#' + modelObj.ref + '-' + curColumnCorr + '-' + missingRow).text('N/A');
            } else {
                console.log(data.items);
            }
            }

            break;
        default:
            console.log('WARNING: Implementation of filling in values for a ' + par + ' parent is pending.');
        }
        }
    }
    }
}, "json");
};

【讨论】:

  • 让您能够解决您的问题。附加说明,以确保您了解var 语句的异常。虽然写for ( var rowID in data.items) { 是有效的,但这可能会给人一种错误的印象,即rowID 的范围只是循环。但正如我已经写过的,只要它存在,你在函数中写var varName 语句的位置很重要。例如for( i=0; i&lt;10; i++) { ... } var i; 与写var i; for( i=0; i&lt;10; i++) { var i; ... }for( var i=0; i&lt;10; i++) { ... } 的效果相同。
猜你喜欢
  • 2010-09-23
  • 1970-01-01
  • 2021-03-28
  • 2018-05-08
  • 2020-02-29
  • 2013-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多