“ X”不是函数-Javascript中的错误

时间:2019-11-14 04:44:03

标签: javascript typeerror

我有以下代码,我已经从其他人那里大致重做以帮助学习JavaScript。我收到以下错误:

Uncaught TypeError: flock.addBoid is not a function
    at setup (boids.js:15)
    at boids.js:1

有问题的函数在setup()的开头调用,并在标记为FLOCK的部分中不久定义。绝对不会拼写错误,这是addBoid在文档中唯一出现的地方。我会把整个文档都包括在内,以防相关,但问题应该只是在开始。

除此错误的来源和解决方案外,我不需要任何有关我的代码的建议,谢谢。

setup();
draw();
//////////////////// SETUP ///////////////////////
var flock;
var ctx;
var c;

function setup(){
    c = document.getElementById("boidCanvas");
    ctx = c.getContext("2d");

    flock = new Flock();
    for(var i = 0; i < 100; i++){
        var b = new Boid(ctx.width / 2, ctx.height / 2);
        flock.addBoid(b);
    }
}

function draw() {
    ctx.fillStyle = "Blue";
    ctx.fillRect(0,0,c.width,c.height);
    //flock.run()
}

//////////////////// FLOCK ///////////////////////
function Flock(){
    this.boids = [];
}

Flock.prototype.run = function(){
    for(var i = 0; i < this.boids.length; i++){
        this.boids[i].run(this.boids);
    }
}

Flock.prototype.addBoid = function(b){
    this.boids.push(b);
}

//////////////////// BOID ///////////////////////
function Boid(setx,sety){
    this.acceleration = { x:0, y:0 };
    this.velocity = { x:Math.floor(Math.random()*3)-1, y:Math.floor(Math.random()*3)-1 };
    this.position = { x:setx, y:sety };
    this.r = 3;
    this.maxSpeed = 3;
    this.maxForce = .05;
}

Boid.prototype.run = function(boids){
    this.evaluate(boids);
    this.update();
    this.wrap();
    this.render();
}

// force is a vector [x,y]
Boid.prototype.applyForce = function(force){
    this.acceleration.x += force[0];
    this.acceleration.y += force[1];
}

Boid.prototype.evaluate = function(boids){
    var seperate = this.seperate(boids);
    var align = this.align(boids);
    var cohesion = this.cohesion(boids);

    // Arbitrary Weights
    seperate *= 1.5;
    align *=    1.0;
    cohesion *= 1.0;

    this.applyForce(seperate);
    this.applyForce(align);
    this.applyForce(cohesion);
}

Boid.prototype.update = function(){
    //update velocity
    this.velocity += this.acceleration;
    //fix velocity to max speed
    var normal = normalize([this.velocity.x, this.velocity.y]);
    this.velocity = constantMult(normal, this.maxSpeed);
    //update position
    this.position.x += this.velocity.x;
    this.position.y += this.velocity.y;
    //reset acceleration;
    this.acceleration.x = 0;
    this.acceleration.y = 0;
}

// target is a vector [x,y]
Boid.prototype.seek = function(target){
    var desired = sub(target, [this.position.x, this.position.y]);

    var normal = normalize(desired);
    desired = constantMult(normal, this.maxSpeed);

    var steer = sub(desired,[this.velocity.x, this.velocity.y])
    normal = normalize(steer);
    steer[0] = normal[0] * this.maxForce;
    steer[1] = normal[1] * this.maxForce;
    return steer;
}

Boid.prototype.render = function(){
    var triangle = drawTriangle(this.velocity);
    for(var i = 0; i < triangle.length; i++){
        triangle[i] = constantMult(triangle[i], this.r);
    }
    for(i = 0; i < triangle.length; i++){
        triangle[i] = add(triangle[i], this.position);
    }
    ctx.beginPath();
    ctx.moveTo(triangle[0][0], triangle[0][1]);
    for(i = 1; i < triangle.length; i++){
        ctx.lineTo(triangle[i][0], triangle[i][1]);
    }
    ctx.closePath();
    ctx.fillStyle = "White";
    ctx.fill();
}

Boid.prototype.wrap = function(){
    if(this.position.x < -this.r)
        this.position.x = c.width + this.r;
    else if(this.position.x > c.width + this.r)
        this.position.x = -this.r;

    if(this.position.y < -this.r)
        this.position.y = c.height + this.r;
    else if(this.position.y > c.height + this.r)
        this.position.y = -this.r;
}

Boid.prototype.seperate = function(boids){
    var desiredSeperation = 25.0;
    var steer = [0,0];
    var count = 0;
    for(var i = 0; i < boids.length; i++){
        var difference = sub(this.position, boids[i].position);
        var d = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
        if(d < desiredSeperation){
            var normalDiff = normalize(difference);
            normalDiff = constantMult(normalDiff, 1/d);
            steer = add(steer, normalDiff);
            count++;
        }
    }
    if(count > 0){
        steer = constantMult(steer, 1/count);

        steer = normalize(steer);
        steer = constantMult(steer, this.maxSpeed);
        steer = sub(steer, this.velocity);
        steer = normalize(steer);
        steer = constantMult(steer, this.maxForce);
    }
    return steer;
}

Boid.prototype.align = function(boids){
    var neighborDistance = 50;
    var sum = [0,0];
    var count = 0;
    for(var i = 0; i < boids.length; i++){
        var difference = sub(this.position, boids[i].position);
        var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
        if(dist < neighborDistance){
            sum = sum(sum, boids[i].velocity);
            count++;
        }
    }
    if(count > 0){
        sum = constantMult(sum, 1/count);
        sum = normalize(sum);
        sum = constantMult(this.maxSpeed);
        var steer = sub(sum, this.velocity);
        steer = normalize(steer);
        steer = constantMult(steer, this.maxForce);
        return steer;
    }
    else
        return [0,0];
}

Boid.prototype.cohesion = function(boids){
    var neighborDistance = 50;
    var sum = [0,0];
    var count = 0;
    for(var i = 0; i < boids.length; i++){
        var difference = sub(this.position, boids[i].position);
        var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
        if(dist < neighborDistance){
            sum = add(sum, boids[i].position);
            count++;
        }
    }
    if(count > 0){
        sum = constantMult(sum, 1/count);
        return this.seek(sum);
    }
    else
        return [0,0];
}

//////////////////// HELPERS ///////////////////////

// returns the vector with the same direction as v but with magnitude 1 in the form [x,y]
// v is a vector in the form [x,y]
function normalize(v){
    var magnitude = Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2))
    var normalX = v[0] / magnitude;
    var normalY = v[1] / magnitude;
    return [normalX, normalY];
}

function add(a,b){
    var x = a[0]+b[0];
    var y = a[1]+b[1];
    return [x,y];
}

// returns a-b,  [ax-bx, ay-by]
function sub(a,b){
    var x = a[0]-b[0];
    var y = a[1]-b[1];
    return [x,y];
}

function mult(a,b){
    var x = a[0]*b[0];
    var y = a[1]*b[1];
    return [x,y];
}

function constantMult(a, n){
    for(var i = 0; i < a.length; i++){
        a[i] *= n;
    }
}

// creates an unscaled issoceles triangle centered at the origin
// returns a list of 3 lists, each containing the coordinates of a vertex, the first being the tip
// ie. [ [x1,y1], [x2,y2], [x3,y3] ]
// heading is a vector describing the direction of the triangle in the form [x,y]
// heading does not need to be normalized
function drawTriangle(heading){
    heading = normalize(heading);
    var v1 = [1,0];
    var v2 = [-1, .5];
    var v3 = [-1,-.5];

    var thetaX = Math.acos(heading[0]);
    var thetaY = Math.asin(heading[1]);
    var theta;

    if(thetaX >= 0)
        theta = (Math.PI / 2) - thetaY;
    else
        theta = (Math.PI / 2) - thetaX;

    function rotate(v){
        var xp = (v[0] * Math.cos(theta)) - (v[1] * Math.sin(theta));
        var yp = (v[1] * Math.cos(theta)) + (v[0] * Math.sin(theta));
        return [xp, yp];
    }

    v1 = rotate(v1);
    v2 = rotate(v2);
    v3 = rotate(v3);

    return [v1,v2,v3];
}

2 个答案:

答案 0 :(得分:4)

将功能setup();draw();移动到JavaScript文件的末尾。问题在于,函数addBoid()并未提升到顶部,从而使setup();draw();无法对其进行定义。

答案 1 :(得分:2)

您的函数声明在该块的顶部得到 hoisted

function Flock(){
    this.boids = [];
}

在为原型添加属性时,这些属性不适合吊装,就像在声明变量之前访问变量(让声明的cause var可以吊装)一样。

Flock.prototype.run = function(){
    for(var i = 0; i < this.boids.length; i++){
        this.boids[i].run(this.boids);
    }
}

Flock.prototype.addBoid = function(b){
    this.boids.push(b);
}

在调用flock.addBoid之前添加上述几行,即将setupdraw调用移至Javascript的结尾

//////////////////// SETUP ///////////////////////
var flock;
var ctx;
var c;

//////////////////// FLOCK ///////////////////////

function Flock(){
    this.boids = [];
}

Flock.prototype.run = function(){
    for(var i = 0; i < this.boids.length; i++){
        this.boids[i].run(this.boids);
    }
}

Flock.prototype.addBoid = function(b){
    this.boids.push(b);
}

function setup(){
    c = document.getElementById("boidCanvas");
    ctx = c.getContext("2d");

    flock = new Flock();
    for(var i = 0; i < 100; i++){
        var b = new Boid(ctx.width / 2, ctx.height / 2);
        flock.addBoid(b);
    }
}

function draw() {
    ctx.fillStyle = "Blue";
    ctx.fillRect(0,0,c.width,c.height);
    //flock.run()
}




//////////////////// BOID ///////////////////////
function Boid(setx,sety){
    this.acceleration = { x:0, y:0 };
    this.velocity = { x:Math.floor(Math.random()*3)-1, y:Math.floor(Math.random()*3)-1 };
    this.position = { x:setx, y:sety };
    this.r = 3;
    this.maxSpeed = 3;
    this.maxForce = .05;
}

Boid.prototype.run = function(boids){
    this.evaluate(boids);
    this.update();
    this.wrap();
    this.render();
}

// force is a vector [x,y]
Boid.prototype.applyForce = function(force){
    this.acceleration.x += force[0];
    this.acceleration.y += force[1];
}

Boid.prototype.evaluate = function(boids){
    var seperate = this.seperate(boids);
    var align = this.align(boids);
    var cohesion = this.cohesion(boids);

    // Arbitrary Weights
    seperate *= 1.5;
    align *=    1.0;
    cohesion *= 1.0;

    this.applyForce(seperate);
    this.applyForce(align);
    this.applyForce(cohesion);
}

Boid.prototype.update = function(){
    //update velocity
    this.velocity += this.acceleration;
    //fix velocity to max speed
    var normal = normalize([this.velocity.x, this.velocity.y]);
    this.velocity = constantMult(normal, this.maxSpeed);
    //update position
    this.position.x += this.velocity.x;
    this.position.y += this.velocity.y;
    //reset acceleration;
    this.acceleration.x = 0;
    this.acceleration.y = 0;
}

// target is a vector [x,y]
Boid.prototype.seek = function(target){
    var desired = sub(target, [this.position.x, this.position.y]);

    var normal = normalize(desired);
    desired = constantMult(normal, this.maxSpeed);

    var steer = sub(desired,[this.velocity.x, this.velocity.y])
    normal = normalize(steer);
    steer[0] = normal[0] * this.maxForce;
    steer[1] = normal[1] * this.maxForce;
    return steer;
}

Boid.prototype.render = function(){
    var triangle = drawTriangle(this.velocity);
    for(var i = 0; i < triangle.length; i++){
        triangle[i] = constantMult(triangle[i], this.r);
    }
    for(i = 0; i < triangle.length; i++){
        triangle[i] = add(triangle[i], this.position);
    }
    ctx.beginPath();
    ctx.moveTo(triangle[0][0], triangle[0][1]);
    for(i = 1; i < triangle.length; i++){
        ctx.lineTo(triangle[i][0], triangle[i][1]);
    }
    ctx.closePath();
    ctx.fillStyle = "White";
    ctx.fill();
}

Boid.prototype.wrap = function(){
    if(this.position.x < -this.r)
        this.position.x = c.width + this.r;
    else if(this.position.x > c.width + this.r)
        this.position.x = -this.r;

    if(this.position.y < -this.r)
        this.position.y = c.height + this.r;
    else if(this.position.y > c.height + this.r)
        this.position.y = -this.r;
}

Boid.prototype.seperate = function(boids){
    var desiredSeperation = 25.0;
    var steer = [0,0];
    var count = 0;
    for(var i = 0; i < boids.length; i++){
        var difference = sub(this.position, boids[i].position);
        var d = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
        if(d < desiredSeperation){
            var normalDiff = normalize(difference);
            normalDiff = constantMult(normalDiff, 1/d);
            steer = add(steer, normalDiff);
            count++;
        }
    }
    if(count > 0){
        steer = constantMult(steer, 1/count);

        steer = normalize(steer);
        steer = constantMult(steer, this.maxSpeed);
        steer = sub(steer, this.velocity);
        steer = normalize(steer);
        steer = constantMult(steer, this.maxForce);
    }
    return steer;
}

Boid.prototype.align = function(boids){
    var neighborDistance = 50;
    var sum = [0,0];
    var count = 0;
    for(var i = 0; i < boids.length; i++){
        var difference = sub(this.position, boids[i].position);
        var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
        if(dist < neighborDistance){
            sum = sum(sum, boids[i].velocity);
            count++;
        }
    }
    if(count > 0){
        sum = constantMult(sum, 1/count);
        sum = normalize(sum);
        sum = constantMult(this.maxSpeed);
        var steer = sub(sum, this.velocity);
        steer = normalize(steer);
        steer = constantMult(steer, this.maxForce);
        return steer;
    }
    else
        return [0,0];
}

Boid.prototype.cohesion = function(boids){
    var neighborDistance = 50;
    var sum = [0,0];
    var count = 0;
    for(var i = 0; i < boids.length; i++){
        var difference = sub(this.position, boids[i].position);
        var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
        if(dist < neighborDistance){
            sum = add(sum, boids[i].position);
            count++;
        }
    }
    if(count > 0){
        sum = constantMult(sum, 1/count);
        return this.seek(sum);
    }
    else
        return [0,0];
}

//////////////////// HELPERS ///////////////////////

// returns the vector with the same direction as v but with magnitude 1 in the form [x,y]
// v is a vector in the form [x,y]
function normalize(v){
    var magnitude = Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2))
    var normalX = v[0] / magnitude;
    var normalY = v[1] / magnitude;
    return [normalX, normalY];
}

function add(a,b){
    var x = a[0]+b[0];
    var y = a[1]+b[1];
    return [x,y];
}

// returns a-b,  [ax-bx, ay-by]
function sub(a,b){
    var x = a[0]-b[0];
    var y = a[1]-b[1];
    return [x,y];
}

function mult(a,b){
    var x = a[0]*b[0];
    var y = a[1]*b[1];
    return [x,y];
}

function constantMult(a, n){
    for(var i = 0; i < a.length; i++){
        a[i] *= n;
    }
}

// creates an unscaled issoceles triangle centered at the origin
// returns a list of 3 lists, each containing the coordinates of a vertex, the first being the tip
// ie. [ [x1,y1], [x2,y2], [x3,y3] ]
// heading is a vector describing the direction of the triangle in the form [x,y]
// heading does not need to be normalized
function drawTriangle(heading){
    heading = normalize(heading);
    var v1 = [1,0];
    var v2 = [-1, .5];
    var v3 = [-1,-.5];

    var thetaX = Math.acos(heading[0]);
    var thetaY = Math.asin(heading[1]);
    var theta;

    if(thetaX >= 0)
        theta = (Math.PI / 2) - thetaY;
    else
        theta = (Math.PI / 2) - thetaX;

    function rotate(v){
        var xp = (v[0] * Math.cos(theta)) - (v[1] * Math.sin(theta));
        var yp = (v[1] * Math.cos(theta)) + (v[0] * Math.sin(theta));
        return [xp, yp];
    }

    v1 = rotate(v1);
    v2 = rotate(v2);
    v3 = rotate(v3);

    return [v1,v2,v3];
}
setup();
draw();