我正在用 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")
}
}
关于代码的其他一些评论:
$("#terminal").css("color", "green");
$("#terminal").text("Element '" + String(key) + "' inserted");
你可以使用这个:
$("#terminal").css("color", "green").text("Element '" + String(key) + "' inserted");
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/