Creando una class de JavaScript simple con jQuery

Intento entender las classs de jQuery pero no está yendo muy bien.

Mi objective es usar una class de esta manera (o para aprender una mejor manera de hacerlo):

var player = new Player($("playerElement")); player.InitEvents(); 

Usando ejemplos de otras personas, esto es lo que intenté:

 $.Player = function ($) { }; $.Player.prototype.InitEvents = function () { $(this).keypress(function (e) { var key = e.which; if (key == 100) { MoveRight(); } if (key == 97) { MoveLeft(); } }); }; $.Player.prototype.MoveRight = function () { $(this).css("right", this.playerX += 10); } $.Player.prototype.MoveLeft = function () { $(this).css("right", this.playerX -= 10); } $.Player.defaultOptions = { playerX: 0, playerY: 0 }; 

El objective final es tener un personaje moviéndose en la pantalla hacia la izquierda y la derecha usando las letras del keyboard A y D

Tengo la sensación de que estoy haciendo algo muy malo con esta "class", pero no estoy seguro de por qué.

(Lo siento por mi ingles)

Un problema importante es que debe asignar el object / elemento jQuery pasado a this.element – u otro this.propertyName – para que pueda acceder a él más tarde dentro de los methods de la instancia.

Tampoco puede llamar a MoveRight() / MoveLeft() directamente así porque esas funciones no están definidas en la cadena de scope, sino en el prototipo del Constructor de su instancia, por lo tanto, necesita una reference a la instancia para llamarlas.

Código actualizado y comentado a continuación:

 (function ($) { //an IIFE so safely alias jQuery to $ $.Player = function (element) { //renamed arg for readability //stores the passed element as a property of the created instance. //This way we can access it later this.element = (element instanceof $) ? element : $(element); //instanceof is an extremely simple method to handle passed jQuery objects, //DOM elements and selector strings. //This one doesn't check if the passed element is valid //nor if a passed selector string matches any elements. }; //assigning an object literal to the prototype is a shorter syntax //than assigning one property at a time $.Player.prototype = { InitEvents: function () { //`this` references the instance object inside of an instace's method, //however `this` is set to reference a DOM element inside jQuery event //handler functions' scope. So we take advantage of JS's lexical scope //and assign the `this` reference to another variable that we can access //inside the jQuery handlers var that = this; //I'm using `document` instead of `this` so it will catch arrow keys //on the whole document and not just when the element is focused. //Also, Firefox doesn't fire the keypress event for non-printable //characters so we use a keydown handler $(document).keydown(function (e) { var key = e.which; if (key == 39) { that.moveRight(); } else if (key == 37) { that.moveLeft(); } }); this.element.css({ //either absolute or relative position is necessary //for the `left` property to have effect position: 'absolute', left: $.Player.defaultOptions.playerX }); }, //renamed your method to start with lowercase, convention is to use //Capitalized names for instanceables only moveRight: function () { this.element.css("left", '+=' + 10); }, moveLeft: function () { this.element.css("left", '-=' + 10); } }; $.Player.defaultOptions = { playerX: 0, playerY: 0 }; }(jQuery)); //so you can use it as: var player = new $.Player($("#playerElement")); player.InitEvents(); 

Violín

También tenga en count que JavaScript no tiene "classs" reales (al less no hasta que se implemente ES6) ni Métodos (que por definición están asociados exclusivamente a Clases), sino Constructores que proporcionan una syntax agradable que se asemeja a las classs. Aquí hay un artículo impresionante escrito por TJ Crowder sobre los methods "falsos" de JS, está un poco avanzado pero todos deberían poder aprender algo nuevo al leerlo:
http://blog.niftysnippets.org/2008/03/mythical-methods.html

Cuando usas this dentro de las funciones de tu prototipo de Player , this apunta al object Jugador actual.

Pero cuando usas $(this).keypress requiere que this apunte a un elemento HTML.

Los dos simplemente son incompatibles. Solo hay uno y apunta al object Player actual, no a un elemento HTML.

Para solucionar su problema, deberá pasar el elemento HTML al object Player en el momento de su creación o en las llamadas a funciones relevantes.

Puede pasar el elemento al object Player en una construcción como esta:

 $.Player = function ($, element) { this.element = element; }; $.Player.prototype.InitEvents = function () { $(this.element).keypress(function (e) { var key = e.which; if (key == 100) { MoveRight(); } if (key == 97) { MoveLeft(); } }); }; $.Player.prototype.MoveRight = function () { $(this.element).css("right", this.playerX += 10); } $.Player.prototype.MoveLeft = function () { $(this.element).css("right", this.playerX -= 10); } $.Player.defaultOptions = { playerX: 0, playerY: 0 };