javascript - 一个涉及 JavaScript 对象结构的错误

标签 javascript debugging

我正在用 JavaScript 编写一个完整的客户端系统。我有大约 4 个 .js 文件,但不需要从它们发布代码,也不需要 html。

无论如何,在解释问题之前,我将尝试解释代码是关于什么的,以及代码本身。

基本上,它是设计级别的有限状态机。目前,我只有 3 个状态:初始状态、转换状态和最终状态(目前,状态机是一个队列)。代码是这样的:

var state = 0

var IntInsert = //my object that represents a namespace, or a set of functions
{
    insertCtrl : function() //main function: it calls the others
    {
        if (lookup()) return
        if (!state) state = 1
        var key = document.getElementById("newegg").value
        switch(state)
        {
            case 1:
                this.preInsert(key)
                break
            case 2:
                this.firstInsert(key)
                break
        }
    },

    preInsert : function(key)
    {
        $("#terminal").css("color", "green")
        $("#terminal").text("Inserting element '" + String(key) + "'")
        $("#t2cell" + String(cuckoohash.h2(key))).css("background-color", "White")
        $("button").prop("disabled", true)
        $("input").prop("disabled", true)
        $("#nextstep").prop("disabled", false)
        state++
    },

    firstInsert : function(key)
    {
        key = [document.getElementById("t1").rows[cuckoohash.h1(key)].cells[0].innerHTML, document.getElementById("t1").rows[cuckoohash.h1(key)].cells[0].innerHTML = key][0] // key <-> t1[h1(key)]
        if (!key)
        {
            $("#t1cell" + String(cuckoohash.h1(document.getElementById("t1").rows[cuckoohash.h1(key)].cells[0].innerHTML))).css("background-color", "LightGreen")
            this.finishedInsert()
        }
    },

    finishedInsert : function()
    {
        $("#terminal").css("color", "green")
        $("#terminal").text("Element '" + String(key) + "' inserted")
    }
}

在 this.firstInsert(key) 行中,发生了一个错误。 Firebug 告诉我:TypeError: this.firstInsert is not a function。这很奇怪,因为它被定义为一个函数,而 Firebug 本身在其高级面板中将其表示为一个函数。

如果我从对象中取出函数并将其用作全局函数,则根本没有错误。这就是为什么我相信可以忽略代码的整个语义来回答我的问题,即:为什么会在对象内部发生这种情况?我错过了什么?

在阅读了公认的答案后,我意识到重要的是要说明代码在对象中的全部意义是为我正在创建的整个状态机代码创建一个命名空间,因此我绝对可以将状态变量放入其中。这个想法是避免拥有带有全局变量和函数的大型代码库。

最佳答案

您的问题可能是由您调用方法的方式引起的。在 Javascript 中,this 的值取决于方法的调用方式,而不是方法的声明方式。您没有显示调用代码(问题可能出在哪里),但是如果您通过某种回调调用您的方法之一,那么您很容易丢失将保留 this 值的正确方法调用为你。见 this other answer有关 this 的值的更多信息取决于函数的调用方式。

有许多不同的可能解决方案。

由于您的对象是单例(只有其中一个,并且您已为该实例命名),因此我建议解决您的问题的最简单方法是仅引用已命名的单例 IntInsert而不是引用this因为这将解决 this 值的任何问题在你的方法中。

你可以这样做:

var state = 0

var IntInsert = //my object that represents a namespace, or a set of functions
{
    insertCtrl : function() //main function: it calls the others
    {
        if (lookup()) return
        if (!state) state = 1
        var key = document.getElementById("newegg").value
        switch(state)
        {
            case 1:
                IntInsert.preInsert(key)
                break
            case 2:
                IntInsert.firstInsert(key)
                break
        }
    },

    preInsert : function(key)
    {
        $("#terminal").css("color", "green")
        $("#terminal").text("Inserting element '" + String(key) + "'")
        $("#t2cell" + String(cuckoohash.h2(key))).css("background-color", "White")
        $("button").prop("disabled", true)
        $("input").prop("disabled", true)
        $("#nextstep").prop("disabled", false)
        state++
    },

    firstInsert : function(key)
    {
        key = [document.getElementById("t1").rows[cuckoohash.h1(key)].cells[0].innerHTML, document.getElementById("t1").rows[cuckoohash.h1(key)].cells[0].innerHTML = key][0] // key <-> t1[h1(key)]
        if (!key)
        {
            $("#t1cell" + String(cuckoohash.h1(document.getElementById("t1").rows[cuckoohash.h1(key)].cells[0].innerHTML))).css("background-color", "LightGreen")
            IntInsert.finishedInsert()
        }
    },

    finishedInsert : function()
    {
        $("#terminal").css("color", "green")
        $("#terminal").text("Element '" + String(key) + "' inserted")
    }
}

关于代码的其他一些评论:
  • 在每条语句的末尾省略分号可能会使您遇到一些意外错误。对我来说,这似乎是一种不太理想的做法。当您第一次看到这样的错误时,您可能会困惑一段时间,为什么您的代码也没有按预期工作。
  • 您可以在 jQuery 中链接,而不是这样:
        $("#terminal").css("color", "green");
        $("#terminal").text("Element '" + String(key) + "' inserted");
    

    你可以使用这个:
        $("#terminal").css("color", "green").text("Element '" + String(key) + "' inserted");
    
  • 在 Javascript 中,您很少需要使用 String(key) 显式转换为字符串。 ,所以不是这个:
        $("#terminal").text("Element '" + String(key) + "' inserted");
    

    你可以使用这个:
        $("#terminal").text("Element '" + key + "' inserted");
    

    向字符串添加任何内容都会自动将其转换为您的字符串。
  • 你很麻烦地制作了一个单例命名空间对象 IntInsert , 但是你声明了你的变量 state那不在那个命名空间对象中。看来您应该做其中之一,而不是两者的奇怪组合。你要么在你的命名空间对象中想要相关的东西,要么不想要像 state 这样的通用命名变量。命名冲突的时机已经成熟。我认为它应该在您的对象中。
  • 混合使用像 $("#terminal") 这样的 jQuery 选择器很奇怪。和 document.getElementById("newegg") .如果您坚持使用一个模型或另一个模型,代码通常会更干净。如果您出于其他原因使用 jQuery,则代码如下:
    var key = document.getElementById("newegg").value;
    

    在 jQuery 中可以是这样的:
    var key = $("#newegg").val();
    
  • .firstInsert() ,您声明一个名为 key 的参数,但是在该方法的第一行代码中,您分配给 key所以代码只是误导。您声明了一个参数,但如果传入该参数,则永远不会使用该参数。您应该使用该参数或更改 key变量只是一个局部变量声明,而不是函数参数。
  • .finishedInsert() ,您引用了一个名为 key 的变量,但没有该名称的此类参数或变量。
  • .firstInsert() ,这行代码很奇怪:
    var key = [document.getElementById("t1").rows[cuckoohash.h1(key)].cells[0].innerHTML, document.getElementById("t1").rows[cuckoohash.h1(key)].cells[0].innerHTML = key][0]; 
    

    您似乎在声明一个包含两个元素的数组,然后仅将第一个元素分配给 key .数组中的第二个元素是对 .innerHTML 的赋值。属性(property)。这只是编写此代码的一种奇怪且具有误导性的方式。它应该被分解成多行代码。
  • .firstInsert() 中的第一行代码似乎是指某种名为 key 的变量的全局定义。它不会出现在您的代码中的任何地方。这可能是个坏主意。 key您在此处使用的应该是在您的命名空间对象中,或者应该作为参数传递给 .firstInsert(xxx) .

  • 这是您的代码的一个版本,其中包含许多以上已修复/修改的项目和 FIXME 注释,其中的事情仍然无法解释:
    //my object that represents a namespace, or a set of functions
    var IntInsert = {
        //main function: it calls the others
        state: 0,
        insertCtrl: function () {
            if (lookup()) return;
            if (!IntInsert.state) IntInsert.state = 1;
            var key = $("#newegg").val();
            switch (IntInsert.state) {
            case 1:
                IntInsert.preInsert(key);
                break;
            case 2:
                IntInsert.firstInsert(key);
                break;
            }
        },
    
        preInsert: function (key) {
            $("#terminal").css("color", "green").text("Inserting element '" + key + "'");
            $("#t2cell" + cuckoohash.h2(key)).css("background-color", "White");
            $("button").prop("disabled", true);
            $("input").prop("disabled", true);
            $("#nextstep").prop("disabled", false);
            IntInsert.state++;
        },
    
        firstInsert: function () {
            // key <-> t1[h1(key)]
            // FIXME here: There is no variable named key anywhere
            document.getElementById("t1").rows[cuckoohash.h1(key)].cells[0].innerHTML = key;
            if (!key) {
                $("#t1cell" + cuckoohash.h1(document.getElementById("t1").rows[cuckoohash.h1(key)].cells[0].innerHTML)).css("background-color", "LightGreen");
                IntInsert.finishedInsert();
            }
        },
    
        finishedInsert: function () {
            // FIXME here: There is no variable named key anywhere
            $("#terminal").css("color", "green").text("Element '" + key + "' inserted");
        }
    };
    

    关于javascript - 一个涉及 JavaScript 对象结构的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36799589/

    相关文章:

    django - 在 VSCode 中调试 Django 在 imp.py 上失败

    ios - 如何在 iOS 中写入图像文件,以便我可以在内置的照片应用程序中打开它们?

    windows - 如何在 Azure 计算模拟器中调用 RoleEntryPoint.OnStop()?

    c - 尝试解决在 C 中连接字符串的问题

    javascript - 为什么这个 JavaScript 不能在 Firefox 中运行?

    javascript - AngularJS - 向子指令提供字符串数组

    javascript - 如何同时设置div的高度和动画宽度

    javascript - 如何将java变量传递到包含javascript的不同jsp页面?

    Javascript 表单提交未正确提交

    .net - mscordacwks.dll 和 mscorwks.dll 混淆