2013-02-16 4 views
0

Здравствуйте, это моя первая попытка попытаться написать приложение JavaScript, поэтому я новичок в написании кода OOP, используя его.Ошибка JavaScript OOP

Следующий код работает без каких-либо ошибок в консоли:

// Main file for the application 
$(document).ready(function() 
{ 
    var app = new application; 
    setInterval(app.run, 50); 

}); 

function application() 
{ 
    var canvas = Raphael(10,0,400,400); 
    this.molecule = new molecule(new Vec2(50,50),new Vec2(1,0),canvas); 
    this.molecule.update(10); 

    this.run = function() 
    { 

    } 
} 

Однако этот кусок кода не работает:

// Main file for the application 
$(document).ready(function() 
{ 
    var app = new application; 
    setInterval(app.run, 50); 

}); 

function application() 
{ 
    var canvas = Raphael(10,0,400,400); 
    this.molecule = new molecule(new Vec2(50,50),new Vec2(1,0),canvas); 

    this.run = function() 
    { 
     this.molecule.update(10); 
    } 
} 

Это дает следующее сообщение об ошибке в консоли:

Uncaught TypeError: Object function molecule(pos,vel,canvas) 
    { 
     this.radius = 5; 
     this.color = "red"; 

     this.canvas = canvas; 

     this.pos = pos; 
     this.vel = vel; 

     this.circle = canvas.circle(this.pos.x,this.pos.y,this.radius); 

     this.circle.attr("fill", this.color); 


    } has no method 'update' 

Вот исходный файл, содержащий объект молекулы.

// This 'class' handles a molecule, including movement and drawing. 

    function molecule(pos,vel,canvas) 
    { 
     this.radius = 5; 
     this.color = "red"; 

     this.canvas = canvas; 

     this.pos = pos; 
     this.vel = vel; 

     this.circle = canvas.circle(this.pos.x,this.pos.y,this.radius); 

     this.circle.attr("fill", this.color); 


    } 

// Updates the molecule 
    molecule.prototype.update = function(deltaTime) 
    { 
     this.pos += this.vel * deltaTime; 
     this.setPosition(this.pos); 
    } 

    // Accepts a Vec2 
    molecule.prototype.setPosition = function(pos) 
    { 
     this.circle.translate(pos.x-this.pos.x, pos.y-this.pos.y); 
    }  

Я извиняюсь за большой объем кода, который я разместил, но я в тупик, почему первая часть кода работает, а второй не будет. Может ли кто-нибудь пролить свет на него для меня? Большое спасибо.

ответ

1

Частая ошибка, и это требует хорошего понимания JavaScript, чтобы увидеть, что здесь происходит. Проблема эта линия:

setInterval(app.run, 50); 

Это заставляет app.run называться, когда интервал закончится без надлежащего this контекста. Для того, чтобы убедиться, что run вызывается с app как его this контексте, вам нужно что-то вроде:

setInterval(function() { 
    app.run(); 
}, 50); 

или с последним JavaScript (только в очень современных браузерах):

setInterval(app.run.bind(app), 50); 

this контекст функция в JavaScript определяется тем, как вызывается функция. В основном, он определяется тем, на какой объект он вызван.Например, в app.run() метод run вызывается на app, и он будет работать, как ожидалось. Однако, в несколько ином сценарии

var fn = app.run; 
fn(); 

функция вызывается не объекта, и, таким образом, this не будет установлено, что приводит к неожиданным результатам. Это именно то, что происходит в вашем случае. Решение состоит в том, чтобы убедиться, что вы передаете функцию, которая может быть вызвана на любом объекте, и вызовите эту функцию run на нужный объект.

+0

Большое спасибо за это! Я новичок в том, как он работает на JavaScript, и просто ожидал, что это будет работать так же, как на других языках. –

+1

@ KarlJacques: Чем скорее вы избавитесь от этого ожидания, тем лучше. Если все языки работают одинаково, то они не будут разными языками. –

0

Вы отделили метод run от app. Передайте функцию, которая удерживает их вместе.

setTimeout(function() { app.run(); }, 50); 

Теперь значение this в .run() будет app объект.


Кроме того, нет никакой необходимости, чтобы сделать новый метод run для каждого application() объекта. Вы можете положить run на application.prototype.

function application() { 
    var canvas = Raphael(10,0,400,400); 
    this.molecule = new molecule(new Vec2(50,50),new Vec2(1,0),canvas); 
    this.molecule.update(10); 
} 

application.prototype.run = function() { 
    this.molecule.update(10); 
} 

Хотя если сделал держать run в конструкторе, вы можете затем его закрыть через переменную, которая ссылается на объект, и поэтому вы можете безопасно отсоединить его.

function application() { 
    var canvas = Raphael(10,0,400,400); 
    this.molecule = new molecule(new Vec2(50,50),new Vec2(1,0),canvas); 
    this.molecule.update(10); 

    var self = this; 

    this.run = function() { 
     self.molecule.update(10); 
    } 
} 

setTimeout(app.run, 50)