【问题标题】:Getting TypeError when trying to call multiline string in p5.js尝试在 p5.js 中调用多行字符串时出现 TypeError
【发布时间】:2016-10-16 06:35:08
【问题描述】:

我一直在尝试找出一个解决方案,将单行句子(我在我的代码中称为“语句”)并在我的草图上将它们转换为多行句子。这个问题与another question I posted on SO 直接相关,我被要求将这个新问题作为一个新问题发布。 @KevinWorkman 的解决方案让我明白了这一点。但是,正在发生的事情是,当我尝试运行该程序时,我得到了一个TypeError: Cannot read property 'display' of undefined。草图加载,但是当我在草图中单击以开始动画时,我得到了那个错误。我认为这是因为我原来的statements[] 数组现在不再是可以在我的draw() 函数中调用的类型。但我的知识不足,无法知道问题出在哪里,而且我查看了所有 JS 和 p5.js 参考资料,但找不到解决方案。

我发布我的完整代码是为了提供一个最小的、完整的、可验证的示例。尽管如此,作为一名作家,我发现“最小”和“完整”是矛盾的术语,因此非常令人困惑,这里是:

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

【问题讨论】:

    标签: javascript string typeerror p5.js


    【解决方案1】:
     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() 方法。您调用 display() 方法的唯一位置是在您的 draw() 函数内,当您循环遍历 statements 数组时。这意味着在某一时刻,您的 statements 数组包含一个未定义的值。您可以通过控制台记录数组来验证这一点。

    我怀疑你有未定义值的原因是因为当你尝试在 setup() 函数中填充 statements 数组时,你只在 for 循环完成后调用 statements[i] = 一次。此时,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() 代替直接赋值来将项目添加到数组中也是一个好主意。

    【讨论】:

    • 我让它与statements[i]... 一起工作。当我将句子分成多行时,问题开始出现。而且,恐怕您对Array.push() 的回答不够具体,我无法理解您的意思,因为我的代码中的多个位置都有直接分配。尝试here 收集您的意思。但是请注意,我正在使用 p5.js,所以 push() has a very specific use 不包含在 array 函数中。谢谢!
    • 在我的答案中添加了更多详细信息以进行澄清。我认为你在这里有一个简单的错字/错误,过早地关闭了 for 循环。我检查了你之前引用的帖子,那里没问题,这里不行。
    • @LesleyLathrop 您可以安全地调用statements.push(),这与调用push() 不同。一个是P5函数,一个是数组函数。为什么在说它不起作用之前不尝试一下?
    • 谢谢,@marton。你是正确的,因为那一行确实需要在你所说的地方。所以感谢你,并为在我的第一条评论中不信任你而道歉。在我多次尝试解决我的问题时,这条线不知何故被移动了。为了使我的素描作品,我还必须做其他事情,但这既不是这里也不是那里。我已经发布了对上述问题的正确答案。
    【解决方案2】:

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

    我首先更改了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 的建议。

    【讨论】:

      【解决方案3】:

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

      让我们看看这些行:

      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 循环,这是我对 your other question 的回答中的位置。

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

      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 模式),因为它可以为您提供有关此类错误的更多信息。

      【讨论】:

      • 实际上,我的错,它确实改变了我把它提高了一个级别。我不确定它是如何移动的,因为我不记得做过。但我查看了我的特朗普版本,在整个过程中我都没有碰过它,这就是你们俩都说应该的地方。但是,恐怕您建议的修复方法比需要的要复杂得多。我已经在下面发布了我的问题的答案。而且,为了记录,请停止说我充满敌意、愤怒或大喊大叫,因为这与事实相去甚远。一个人直接而不被指责侵略是不是可以的?
      • @LesleyLathrop 我的答案比它需要的复杂得多吗? Marton 告诉你将语句移到循环中,你说那行不通,所以我解释了为什么答案确实是正确的。您发布的答案在哪里?
      • @LesleyLathrop 我说的是当我要求您发布此后续问题而不是修改已经回答的现有问题时,您在上一个问题中采用的语气。这就是堆栈溢出的工作方式。出于某种原因,您还对 [mcve]minimal reproducible example 的自动扩展反应非常消极。我只是想再次避免这种反应。我来这里是为了帮助人们,而不是卷入琐碎的争吵中。如何继续由您决定,但为了记录,大写字母意味着在互联网上大喊大叫。
      • 我将发表最后一条评论,然后继续前进,因为您误解了我的 cmets 并且没有兴趣接受我没有伤害或不尊重的意思。作为记录,在互联网上将一两个单词大写也意味着“强调这一点”,因为通常我们没有加粗或斜体的选项。我知道我们可以在这里做到这一点,但这是我习惯的习惯。最后,我并没有“争吵”或“打架”。我一直试图向你解释我完全无害的意图,但你似乎不愿意真正听到。因此,我承认。
      • @LesleyLathrop 我已经回答了你最近提出的问题的 3/3。我正在努力帮助你。当我要求您发布后续问题而不是添加令人困惑的编辑时,您说您不会那样做,并补充说我“不再需要提醒您”包括minimal reproducible example,即使那不是我在做什么。这就是我认为的敌对答复。如果这不是你的意图,那很好。祝你有美好的一天。
      猜你喜欢
      • 1970-01-01
      • 2016-05-30
      • 2020-05-10
      • 2019-05-25
      • 1970-01-01
      • 1970-01-01
      • 2018-04-24
      • 1970-01-01
      • 2022-10-21
      相关资源
      最近更新 更多