【问题标题】:JS - Error: "Cannot read property of undefined"JS - 错误:“无法读取未定义的属性”
【发布时间】:2017-07-01 00:13:47
【问题描述】:

我正在尝试使用 P5.JS 库在 JavaScript 中进行遗传算法模拟,但我遇到了一些问题。这是我目前所拥有的:

//var popS = 2;
var popu;
//var balls = [];
var target;

function setup() {
  createCanvas(800, 300);
  popu = new Population();
  target = createVector(width - 15, height / 2);
}

function draw() {
  background(50);
  popu.run();

  var ballsC = 0;
  for (var a = 0; a < popu.balls.length; a++) {
    if (popu.balls[a].done == true){ 
      ballsC ++;
    }
  }
  if (ballsC >= popu.popS) {
    //popu = new Population();
    popu.evaluate();
    //popu.selection();
  }

  fill(255, 0, 30);
  noStroke();
  ellipse(target.x, target.y, 20, 20);
}

function DNA() {
  this.genes = [];
  this.changes = 7;//random(2, 50);

  for (var a = 0; a < this.changes; a++) {
    this.genes[a] = random(0, 15);
  }

  this.crossover = function (pB) {
    var newdna = new DNA();
    var mid = floor(random(0, this.genes.length));
    for (var a = 0; a < this.genes.length; a++) {
      if (a < mid) {
        newdna.genes[a] = this.genes[a];
      }else {
        newdna.genes[a] = pB.genes[a];
      }
    }
    return newdna;
  }
}

function Population() {
  this.balls = [];
  this.popS = 50;
  this.maxfit = 0;
  this.matingpool = [];

  for (var a = 0; a < this.popS; a++) {
    this.balls[a] = new Ball();
  }

  this.evaluate = function() {
    for (var a = 0; a < this.balls.length; a++) {
      this.balls[a].calcF();
      if (this.balls[a].fitness > this.maxfit) {
        this.maxfit = this.balls[a].fitness;
      }
    }
    this.matingpool = [];
    for (var b = 0; b < this.balls.length; b++) {
      var n = this.balls[b].fitness * 100;
      for (var c = 0; c < n; c++) {
        this.matingpool.push(this.balls[c]);
      }
    }

    this.selection();
  }

  this.selection = function () {
    var newBalls = [];
    for (var a = 0; a < this.balls.length; a++) {
      var parentA = this.matingpool[floor(random(0, this.matingpool.length))];
      var parentB = this.matingpool[floor(random(0, this.matingpool.length))];
      var child = parentA.dna.crossover(parentB.dna);
      newBalls[a] = new Ball(child);
    }
    this.balls = newBalls;
  }

  this.run = function() {
    for (var a = 0; a < this.balls.length; a++) {
      this.balls[a].update();
      this.balls[a].checkCol();
      this.balls[a].show();
    }
  }
}

function Ball(dna) {
  this.pos = createVector(10, height / 2);
  this.speed = createVector(2, 2.5);
  this.mul = -1;
  this.time = 0;
  this.a = 0;
  if (dna) {
    this.dna = dna;
  } else {
    this.dna = new DNA();
  }
  this.done = false;
  this.fitness = 0;
  this.reached;

  this.update = function() {
    if (this.done == false) {
      if (this.time >= this.dna.genes[this.a]) {
        this.a++;
        this.time = 0;
        this.mul *= -1;
      }
      this.speed.set(2, 2.5 * this.mul);
      this.pos.add(this.speed);
    }
  }

  this.show = function() {
    this.time += 0.1;
    fill(255, 70);
    noStroke();
    ellipse(this.pos.x, this.pos.y, 10, 10);
  }

  this.checkCol = function() {
    if (this.pos.y > height || this.pos.y < 0 || this.pos.x > width) {
      //print("col");
      this.done = true;
    }
    if (dist(this.pos.x, this.pos.y, target.x, target.y) <= (10 / 2) + (20 / 2)) {
      //print("done!");
      this.done = true;
      this.reached = true;
    }
  }

  this.calcF = function() {
    var a = dist(this.pos.x, this.pos.y, target.x, target.y);
    var b = this.dna.genes.length;
    var c = 0;
    if (this.reached){
      c = 1;
    }

    this.fitness = map(map(a, 0, width, 1, 0) + map(b, 2, 50, 1, 0) + c, 0, 3, 0, 1);
  }
}

这是代码中最重要的部分:

var popu;

function setup() {
  createCanvas(800, 300);
  popu = new Population();
}

function draw() {
  background(50);
  //popu = new Population();
  popu.evaluate();
  //popu.selection();
}

function DNA() {
  this.genes = [];
  this.changes = 7; //random(2, 50);

  for (var a = 0; a < this.changes; a++) {
    this.genes[a] = random(0, 15);
  }

  this.crossover = function(pB) {
    var newdna = new DNA();
    var mid = floor(random(0, this.genes.length));
    for (var a = 0; a < this.genes.length; a++) {
      if (a < mid) {
        newdna.genes[a] = this.genes[a];
      } else {
        newdna.genes[a] = pB.genes[a];
      }
    }
    return newdna;
  }
}

function Population() {
  this.balls = [];
  this.popS = 50;
  this.maxfit = 0;
  this.matingpool = [];

  for (var a = 0; a < this.popS; a++) {
    this.balls[a] = new Ball();
  }

  this.evaluate = function() {
    this.matingpool = [];
    for (var b = 0; b < this.balls.length; b++) {
      var n = this.balls[b].fitness * 100;
      for (var c = 0; c < n; c++) {
        this.matingpool.push(this.balls[c]);
      }
    }

    this.selection();
  }

  this.selection = function() {
    var newBalls = [];
    for (var a = 0; a < this.balls.length; a++) {
      var parentA = this.matingpool[floor(random(0, this.matingpool.length))];
      var parentB = this.matingpool[floor(random(0, this.matingpool.length))];
      var child = parentA.dna.crossover(parentB.dna);
      newBalls[a] = new Ball(child);
    }
    this.balls = newBalls;
  }
}

function Ball(dna) {
  this.pos = createVector(10, height / 2);
  this.speed = createVector(2, 2.5);
  this.mul = -1;
  this.time = 0;
  this.a = 0;
  if (dna) {
    this.dna = dna;
  } else {
    this.dna = new DNA();
  }
  this.done = false;
  this.fitness = 0;
  this.reached;

}

所以每当它到达这里:

this.selection = function () {
    var newBalls = [];
    for (var a = 0; a < this.balls.length; a++) {
      var parentA = random(this.matingpool);
      var parentB = random(this.matingpool);
      var child = parentA.dna.crossover(parentB.dna);
      newBalls[a] = new Ball(child);
    }
    this.balls = newBalls;
  }

我收到错误:“无法读取未定义的属性 'dna'”,到底为什么会发生这种情况?当我在 chrome 中使用调试器时,我可以清楚地看到 matingpool 有 2000 个元素,但是当我尝试获取随机元素时,它返回“未定义”。

var parentA = random(this.matingpool);
var parentB = random(this.matingpool);

奇怪的是 parentB 可以工作,但 parentA 不能。

非常感谢任何帮助。整个代码在这里运行:http://codepen.io/felipe_mare/pen/bgOYMN

如果有帮助,我有时会在第 138 行收到错误:“无法读取未定义的属性 '0'”

this.update = function() {
    if (this.done == false) {
      //line 138
      if (this.time >= this.dna.genes[this.a]) {
      //line 138
        this.a++;
        this.time = 0;
        this.mul *= -1;
      }
      this.speed.set(2, 2.5 * this.mul);
      this.pos.add(this.speed);
    }
  }

【问题讨论】:

  • 你的random()看起来怎么样?
  • @JohanP 请注意p5.js 标签。 P5.js 库提供了random() 函数。
  • 第 138 行是哪一行?
  • @AndrewLi if (this.time &gt;= this.dna.genes[this.a]) { 不好编辑,抱歉
  • 有没有机会将其缩小到minimal reproducible example 而不是整个草图?只有几个对象的更基本的示例会更容易调试。

标签: javascript genetic-algorithm p5.js codepen


【解决方案1】:

今后,请尽量将您的问题缩小到MCVE。我知道这是一个复杂的调试问题,但如果您尝试将问题缩小到 minimal(不到 20 行)示例,您的运气会好得多。大多数情况下,您最终会在创建 MCVE 的过程中发现错误。

但你的问题实际上是当你创建 matingpool 数组时,这里:

this.matingpool = [];
for (var b = 0; b < this.balls.length; b++) {
  var n = this.balls[b].fitness * 100;
  for (var c = 0; c < n; c++) {
    this.matingpool.push(this.balls[c]);
  }
}

如果我在内部 for 循环中添加一个打印语句,如下所示:

this.matingpool = [];
for (var b = 0; b < this.balls.length; b++) {
  var n = this.balls[b].fitness * 100;
  for (var c = 0; c < n; c++) {
    console.log("pushing: " + this.balls[c]);
    this.matingpool.push(this.balls[c]);
  }
}

然后我看到你多次将undefined 推入数组:

(1178) pushing: [object Object]
(3) pushing: undefined
(482) pushing: [object Object]
(3) pushing: undefined
(216) pushing: [object Object]

然后你从这个数组中随机选择,这就是你的错误出现在代码中随机位置的原因。

您将不得不进一步调试它以找出发生这种情况的原因 - 您基于适应度而不是数组长度进行循环似乎很奇怪,但我对代码的理解还不够好确定。无论如何,希望这能让您走上正轨。

【讨论】:

  • 当你给它一个数组时,它会返回一个随机元素
  • @Pepe 哇哦。从来不知道。整洁的。当我弄清楚时,我会继续挖掘和编辑我的答案。
  • 我也试过this.matingpool[floor(random(0, this.matingpool.length))]; 还是不行
  • 是的,应该是this.matingpool.push(this.balls[b]);。尽管如此,仍然得到“无法读取未定义的属性'0'”,猜测我必须进一步研究它。非常感谢您的帮助,祝您有美好的一天。
  • 耶它的工作!看看:codepen.io/felipe_mare/pen/bgOYMN 再次感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2015-02-05
  • 2020-10-15
  • 2021-09-20
  • 1970-01-01
  • 2021-12-31
  • 2022-10-05
  • 2022-01-16
相关资源
最近更新 更多