尝试在 p5.js 中调用多行字符串时出现 TypeError

Getting TypeError when trying to call multiline string in p5.js

我一直在尝试找出一种解决方案,将单行句子(我在我的代码中称为 "statements")并在我的草图上将它们变成多行句子。这个问题与 another question I posted on SO 直接相关,我被要求 post 这个新问题作为一个新问题。 @KevinWorkman 的解决方案让我明白了这一点。但是,当我尝试 运行 程序时,我得到了一个 TypeError: Cannot read property 'display' of undefined。加载了草图,但是当我在草图中单击以启动动画时,出现了该错误。我认为这是因为我原来的 statements[] 数组现在不再是可以在我的 draw() 函数中调用的类型。但是我的知识不够了解问题是什么,我已经查看了我所有的 JS 和 p5.js 参考资料,但找不到解决方案。

我正在 post 编写我的完整代码,以努力提供一个最小的、完整的、可验证的示例。尽管事实上,作为一名作家,我发现 "minimal" 和 "complete" 是相互矛盾的术语,因此非常令人困惑,这里是:

var clContext;
var speed = 0.8;
var statements = [];
var canvas;

//load the table of Clinton's statements and their polarity
function preload() {
  clContext = loadTable("cl_context_rev.csv", "header");
}

function setup() {
  canvas = createCanvas(680, 420);
  canvas.mousePressed(inWidth);
  background(51);
  noStroke();
  // iterate over the table rows called in 'preload()' from .csv file
  for (var i = 0; i < clContext.getRowCount(); i++) {
    var statement = clContext.get(i, "statement");
    var polarity = clContext.get(i, "polarity");
    }
    statements[i] = new Statement(polarity, statement);
  }

function draw() {
  if (mouseIsPressed) {
    background(51);
    for (var i = 0; i < statements.length; i++) {
      statements[i].display();
    }
  }
}

// Function to align statements, categories, and polarity
function Statement(polarity, statement) {
  // Break up single-line statements in order to display as multiline
  this.statement = split(statement, "<br>");
  this.polarity = polarity;
  this.x = random(width);
  this.y = random(height);
  this.dx = random(-speed, speed);
  this.dy = random(-speed, speed);
}
// Attach pseudo-class methods to prototype;
// Maps polarity to color and x,y to random placement on canvas
Statement.prototype.display = function() {
  this.x += this.dx;
  this.y += this.dy;

// Make statements reappear if they move off of the sketch display
  if(this.x > width+10){
    this.x = -10
  }
  if(this.y > height+10) {
    this.y = -10
  }
// Map positive/negative statements to colors
  if(this.polarity == -1){
    fill(229,121,59);
  }
  else if(this.polarity == 1){
    fill(97,93,178);
  }
  textSize(14);
  // Was directed to add both 'text' statements
  text(this.statement[0], this.x, this.y);
  text(this.statement[1], this.x, this.y+25);
}

// Create functions for hiding and showing statements
function inWidth() {
  width = width+5;
};  

注:

console.log(typeof this.statement[0])  // returns 'undefined'
console.log(typeof this.statement[1])  // returns 'undefined'
console.log(split(statement, "<br>"))  // returns 'undefined'  

console.log(statements) // returns 'object'
console.log(statements.length) // returns 20
 for (var i = 0; i < clContext.getRowCount(); i++) {
  var statement = clContext.get(i, "statement");
  var polarity = clContext.get(i, "polarity");
 }
 statements[i] = new Statement(polarity, statement);

我认为这里的最后一行应该在 for 循环内,以便执行您想要的操作。

您的错误意味着您正试图对未定义的值调用 display() 方法。当循环遍历 statements 数组时,调用 display() 方法的唯一位置是在 draw() 函数内部。这意味着您的 statements 数组在某一时刻包含一个未定义的值。您可以通过控制台记录数组来验证这一点。

我怀疑你有未定义值的原因是因为当你试图在 setup() 函数中填充语句数组时,你只调用 statements[i] = 一次,在你的 for 循环完成后。此时 i 的值是 for 循环结束时的值,因此您的 statements 数组成为一个数组,其中第 i 个元素是您设置的任何值,所有先前的元素都是未定义。

正确代码:

 for (var i = 0; i < clContext.getRowCount(); i++) {
  var statement = clContext.get(i, "statement");
  var polarity = clContext.get(i, "polarity");
  statements[i] = new Statement(polarity, statement);
  // OR statements.push(new Statement(polarity, statement));
 }

作为通用的 JavaScript 编码风格原则,使用 Array.push() 而不是直接赋值来将项目添加到数组也是一个好主意。

马顿的回答是正确的。我给它一个 upvote,我认为你应该接受它。但我会尝试对其进行扩展,因为我不确定您是否理解它在说什么。

让我们看看这些行:

for (var i = 0; i < clContext.getRowCount(); i++) {
    var statement = clContext.get(i, "statement");
    var polarity = clContext.get(i, "polarity");
}
statements[i] = new Statement(polarity, statement);

请 运行 通过此代码和一些示例数据。假设您有 3 行。

  • 你第一次运行通过循环,i0。你得到一个 statement 和一个 polarity,但你不对它们做任何事情。
  • 你第二次运行通过循环,i1。你得到一个 statement 和一个 polarity,但你不对它们做任何事情。
  • 你第三次运行通过循环,i2。你得到一个 statement 和一个 polarity,但你不对它们做任何事情。
  • 然后循环退出。 statementpolarity 变量超出范围,因此它们是 undefined。与 i 变量相同。

基本上,该循环不执行任何操作。然后我们到达这一行:

statements[i] = new Statement(polarity, statement);

但我们知道 ipolaritystatement 是未定义的,所以您真正要做的是:

statements[undefined] = new Statement(undefined, undefined);

你说这个有用,但我很怀疑。你在这里做什么没有任何意义。该语句绝对属于 for 循环,这是我对 .

的回答中的位置

但是按照您现在的方式,数组中没有添加任何内容,除了未定义索引处的内容。那么我们就到了这一行:

for (var i = 0; i < statements.length; i++) {
  statements[i].display();
}

现在,我敢打赌 statements.length 是 1,因为您在一个未定义的索引处有一些东西(也许那个索引是 i 的最后一个值,我不知道)。但是您肯定在索引 0 处没有任何内容。那么当你进入这个循环时,i0,但你在那个索引处没有任何东西。换句话说,statements[0] 是未定义的。所以内线真的是这样做的:

undefined.display();

这就是导致您出错的原因。解决第一个问题将消除此错误,因为您实际上是在向数组中添加内容。

此外,请注意以下几行:

// Was directed to add both 'text' statements
  text(this.statement[0], this.x, this.y);
  text(this.statement[1], this.x, this.y+25);

我给你的这段代码只是一个例子。你必须在这里做一些更智能的事情。我只是向您展示了如何访问 statement 数组的两个索引。您必须实际检查此数组的长度并循环遍历句子才能执行某些操作。那是什么完全取决于你想要发生什么。

关于一般调试

您似乎遇到了很多问题,因为您试图同时处理所有事情。如果您开始以更小的块工作,您会省去很多麻烦。与其尝试将此功能添加到您的大主草图中,不如尝试先让一个较小的示例草图工作?尝试对这些值进行硬编码,这样您就可以准确地看到 split() 函数发生了什么。使用 println() 语句来了解发生了什么。尝试一次添加所有内容只会让您和我们感到困惑。

请注意,这不是对 MCVE 的请求(因为我上次提到它时你很生气),但老实说,你能做的最好的帮助自己的事情就是从更小的步骤开始工作。

您也可以考虑切换到常规处理(Java 模式),因为它可以为您提供有关此类错误的更多信息。

我终于能够通过对代码进行一些简单的更改来解决此问题。一旦我想到它,它似乎非常明显,我完全不确定为什么我花了这么长时间才弄明白。

我首先更改 setup() 代码:

function setup() {
  canvas = createCanvas(680, 420);
  canvas.mousePressed(inWidth);
  background(51);
  noStroke();
  // iterate over the table rows called in 'preload()' from .csv file
  for (var i = 0; i < clContext.getRowCount(); i++) {
    var statement = clContext.get(i, "statement");
    var polarity = clContext.get(i, "polarity");
    var stateSplit = split(statement, "<br>");            // split the statements in setup to avoid issues elsewhere
      for (var j = 0; j < stateSplit.length; j++) {
        var stateJoin = join(stateSplit, "\n");           // join the statements, inserting a line break, to make a new array
      statements[i] = new Statement(polarity, stateJoin); // put this in the for loop (per @marton)
    }
    }
}

然后我修改了我的构造函数和原型显示函数如下:

摆脱了这个,因为它只分解了语句,但没有加入它们:

  this.statement = split(statement, "<br>"); 

并将其替换为:

  this.stateJoin = stateJoin;                  

然后我摆脱了这些:

text(this.statement[0], this.x, this.y);
text(this.statement[1], this.x, this.y+25); 

并改用这个:

    text(this.stateJoin, this.x, this.y)              

瞧!感谢@marton 和@KevinWorkman 的建议。