2014-04-24 3 views
0

Я пытаюсь создать javascript «класс», и он работает несколько хорошо, но Engine.tile.draw работает не так, как предполагалось. Кажется, я не могу заставить его работать внутри Engine.start. Невозможно создать объект и добавить внутри него функцию, как я? Как вы, ребята, это сделаете? Любая помощь приветствуется. :)Создание класса javascript с объектом, содержащим функции

var EngineClass = (function() { 
    var Engine = function() { 
     this.canvas = document.getElementById('game'); 
     this.handle = this.canvas.getContext('2d'); 
    }; 

    Engine.prototype.start = function (mapData) { 
     this.tile.draw(mapData); 
    }; 

    Engine.prototype.tile = { 
     draw: function (x, y, tile) { 
     this.handle.fillText(tile, x * 16, y * 16); 
     }; 
    } 

    return Engine; 
})(); 

var Engine = new EngineClass(); 
+1

Javascript является прообраз на основе объектно-ориентированном языком (http://en.wikipedia.org/ wiki/Prototype-based_programming), а не ориентированный на класс язык, ориентированный на объект. Просто не делай этого. Вы бы не построили двигатель газонокосилки в свой автомобиль, поэтому не создавайте классы в JS. – schlingel

+1

В javascript нет классов – defau1t

+0

Вот почему я сказал «класс».Я знаю, что в текущей версии av ECMA нет классов, но это общий способ ее эмулировать. Но часть, где я пытаюсь добавить функции внутри объекта (Engine.tile), не является распространенной, я думаю, поскольку она не работает. – Jan

ответ

0

Это действительно не работает использовать суб -bjects, как вы здесь:

Engine.prototype.tile = { 
    draw: function (x, y, tile) { 
    this.handle.fillText(tile, x * 16, y * 16); 
    }; 
} 

Вопрос заключается в том, что при вызове Engine.tile.draw(), то this указатель внутри метода draw() будет установите для объекта tile, который не является вашим кодом (ваш код предполагает, что this указывает на пример Engine, который не является тем, что происходит).

Если вам действительно нужен подобъект подобным образом, тогда вам нужно будет инициализировать этот под-объект в конструкторе Engine, чтобы каждый объект tile был настроен однозначно, и тогда вам нужно будет добавить его указатель на двигатель tile данных экземпляра, так что, когда вызывается Engine.tile.draw(), вы можете получить соответствующий экземпляр Engine из указателя this, который указывает на объект tile. Но это все беспорядок и, вероятно, и ненужный, и трудный способ делать что-то.

Возможно, вы либо сделаете tile своим собственным объектом с его собственными данными экземпляра, либо поместите метод draw на объект Engine и просто передадите ему некоторые аргументы, которые помогут ему выполнить свою работу.

+0

Я ценю ваш ответ, спасибо. Итак, в основном, ваша рекомендация - сделать «плитку» своим собственным объектом? Плитка будет содержать МНОГО позже, поэтому я думаю, что это хорошая идея. – Jan

+0

@Jan - если 'tile' будет иметь множество операций и собственных данных, тогда да, вы должны сделать его своим собственным объектом. Если для 'draw()' самой, ему нужно знать «дескриптор», который он должен использовать для рисования, тогда, возможно, это должно быть сохранено в данных экземпляра 'tile', чтобы он мог выполнять' draw() 'метод сам по себе. Или, альтернативно, вы можете иметь в каждой «плитке» ссылку на свой родительский «Двигатель», и вы можете получить «ручку» оттуда. Дело в том, что когда методы вызываются на объект 'tile', указатель' this' будет объектом 'tile'. – jfriend00

0

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

Технически причина, по которой это не работает, заключается в том, что всякий раз, когда вы вызываете функцию с использованием точечной нотации (например, something.method()), функция вызывается с this, связанной с левой стороной точки. Таким образом, в этом случае, когда вы говорите this.tile.draw(mapData), функция tile.draw вызывается с , являющимся объектом tile, а не объектом Engine, как и следовало ожидать.

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

0

Потому что внутри draw функция будет ссылаться на объект Engine.prototype.tile, а не то, что вы ожидали.

Изменить

Engine.prototype.tile = { 
    draw: function (x, y, tile) { 
    this.handle.fillText(tile, x * 16, y * 16); 
    }; 
} 

в

Engine.prototype.tile = function() { 
    var self = this; 
    return { 
    draw: function (x, y, tile) { 
     self.handle.fillText(tile, x * 16, y * 16); 
    }; 
    }; 
} 

И называют это нравится:

Engine.prototype.start = function (mapData) { 
    this.tile().draw(mapData); 
}; 
Смежные вопросы