使用jQuery创建一个简单的JavaScript类

我正在尝试理解jQuery类,但它不是很顺利。

我的目标是以这种方式使用类(或者学习更好的方法):

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

使用其他人的例子,这就是我尝试过的:

 $.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 }; 

最终目标是使用键盘字母AD左右移动屏幕上的角色。

我有一种感觉,我正在做这个“课”的非常错误,但我不确定为什么。

(对不起我的英语不好)

一个重要的问题是你必须将传递的jQuery对象/元素分配给this.element – 或另一个this.propertyName – 以便稍后可以在实例的方法中访问它。

你也不能直接调用MoveRight() / MoveLeft() ,因为这些函数没有在作用域链中定义,而是在实例的构造函数的原型中定义,因此你需要引用实例本身来调用它们。

更新和评论的代码如下:

 (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(); 

小提琴

另请注意,JavaScript没有实际的“类”(至少在ES6实现之前),也没有方法(根据定义只与Classes关联),而是提供类似于类的甜蜜语法的构造函数。 这是一篇由TJ Crowder撰写的关于JS“假”方法的精彩文章,它有点先进,但每个人都应该能够从阅读中学到新东西:
http://blog.niftysnippets.org/2008/03/mythical-methods.html

Player原型函数中使用thisthis指向当前的Player对象。

但是当你使用$(this).keypress它需要指向一个HTML元素。

这两者简直是不相容的。 只有一个,它指向当前的Player对象,而不是HTML元素。

要解决您的问题,您需要在创建时将HTML元素传递给Player对象,或者传递到相关的函数调用中。

你可以在构造时将元素传递给Player对象,如下所示:

 $.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 };