涉及JavaScript对象结构的错误

时间:2016-04-22 17:03:55

标签: 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不是函数。这很奇怪,因为它被定义为一个函数而Firebug本身将它表示为它的高级面板中的一个函数。

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

在阅读了确认的答案后,我意识到重要的是要声明对象中的代码的重点是为我正在创建的整个状态机代码创建一个命名空间,所以我绝对可以把状态变量放到在里面。我们的想法是避免使用具有全局变量和函数的大型代码库。

3 个答案:

答案 0 :(得分:1)

您看到错误的原因很可能是因为在运行时&#39;这个&#39;正在改变一个没有你功能的对象。尝试重组你的代码和&#34;关闭&#34; this就像这样:

var IntInsert = function()
{
    var self = this;
    ...
    var insertCtrl = function() //main function: it calls the others
    {
        ... 
        case 2:
            self.firstInsert(key)
            break
        ...
    }
    ...

    var firstInsert = function(key)
    {
        ...
    }

    return {
        insertCtrl: insertCtrl,
        firstInsert: firstInsert
    }
}

......或类似的东西,以满足您的需求。

答案 1 :(得分:1)

我认为您在调用函数时遇到this的问题。您尚未显示调用函数的方式,但很可能在您在该行之前记录this时,它不是您的IntInsert对象,但可能是global Window对象

答案 2 :(得分:1)

您的问题很可能是由您调用方法引起的。在Javascript中,this的值取决于方法的调用方式,而不是如何声明方法。你没有显示调用代码(可能出现问题的地方),但是如果你通过某种回调调用你的一个方法,那么你很容易丢失正确的方法调用来保存{{{ 1}}给你。有关如何根据函数的调用方式确定this的值的详细信息,请参阅this other answer

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

由于你的对象是一个单身人士(只有他们中的一个,并且你给了一个实例一个名字),我建议解决你问题的最简单方法是只是引用命名的单例this而不是引用IntInsert,因为这将解决方法中this值的任何问题。

你可以这样做:

this

关于守则的其他一些评论:

  1. 在每个声明的末尾遗漏分号可能会让您遇到一些意外错误。对我来说,这似乎是一种不太理想的做法。第一次看到这样的错误时,你可能会感到困惑,因为你的代码也没有按照预期的那样工作。

  2. 你可以链接jQuery而不是这个:

    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")
        }
    }
    

    您可以使用:

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

    String(key)

    您可以使用:

        $("#terminal").text("Element '" + String(key) + "' inserted");
    

    向字符串添加任何内容会自动将其自动转换为字符串。

  4. 您遇到了制作单例命名空间对象 $("#terminal").text("Element '" + key + "' inserted"); 的麻烦,但您声明了不在该命名空间对象中的变量IntInsert。看来你应该做其中一个,而不是两个奇怪的组合。您要么想要命名空间对象中的相关内容,要么state这样的通用命名变量适用于命名冲突。我认为它应该在你的对象中。

  5. 使用jQuery选择器(如state$("#terminal")的混合物很奇怪。如果您坚持使用一种型号或另一种型号,代码通常更清晰。如果您出于其他原因使用jQuery,那么代码如下:

    document.getElementById("newegg")

    可以在jQuery中使用:

    var key = document.getElementById("newegg").value;
    
  6. var key = $("#newegg").val(); 中,您声明了一个名为.firstInsert()的参数,但是在该方法的第一行代码中,您分配给key,因此代码只是误导。您声明了一个参数,但是如果传入它则永远不会使用该参数。您应该使用参数或将key变量更改为局部变量声明,而不是函数参数。

    < / LI>
  7. key中,您引用一个名为.finishedInsert()的变量,但该名称没有此类参数或变量。

  8. 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属性的赋值。这只是编写此代码的一种奇怪且误导性的方式。它应分解为多行代码。

  9. .innerHTML中的第一行代码似乎是指某个名为.firstInsert()的变量的全局定义,它不会出现在代码中的任何位置。这可能是一个坏主意。您在此处使用的key应位于您的命名空间对象中,或者应作为参数传递给key

  10. 这是您的代码的一个版本,其中包含上述修复/修改的项目以及FIXME注释,其中的内容仍然无法解释:

    .firstInsert(xxx)