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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14418214/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 16:41:15  来源:igfitidea点击:

Creating a simple JavaScript class with jQuery

javascriptjqueryclasskeyboard-events

提问by samy

I'm trying to understand jQuery classes but it is not going very well.

我正在尝试了解 jQuery 类,但进展并不顺利。

My goal is to use a class this way (or to learn a better way to do it):

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

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

Using other people's examples, this is what I tried:

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

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

The end goal is to have a character moving on the screen left and right using the keyboard letters Aand D.

最终目标是使用键盘字母A和使角色在屏幕上左右移动D

I have a feeling that I'm doing something very wrong with this "class" but I'm not sure why.

我有一种感觉,我在这个“课程”上做错了什么,但我不知道为什么。

(sorry for my English)

(对不起我的英语不好)

回答by Fabrício Matté

An important issue is that you have to assign the passed jQuery object/element to a this.element- or another this.propertyName- so you can access it later inside the instance's methods.

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

You also cannot call MoveRight()/MoveLeft()directly like that because those functions are not defined up in the scope chain, but rather in the prototype of your instance's Constructor, hence you need a reference to the instance itself to call these.

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

Updated and commented code below:

更新和评论以下代码:

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

Fiddle

小提琴

Also note that JavaScript does not have actual "classes" (at least not until ES6 gets implemented) nor Methods (which by definition are associated exclusively to Classes), but rather Constructors which provide a sweet syntax that resembles classes. Here's an awesome article written by TJ Crowder regarding JS's "fake" methods, it is a little advanced but everyone should be able to learn something new from reading it:
http://blog.niftysnippets.org/2008/03/mythical-methods.html

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

回答by Frank van Puffelen

When you use thisinside your Playerprototype functions, thispoints to the current Player object.

当您thisPlayer原型函数中使用时,this指向当前的 Player 对象。

But when you use $(this).keypressit requires that thispoints to an HTML element.

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

The two simply are incompatible. There is only one thisand it points to the current Player object, not to an HTML element.

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

To fix your problem, you will need to pass the HTML element into the Player object upon its creation or into the relevant function calls.

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

You can pass the element into the Player object upon construction like this:

您可以在构造时将元素传递给 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
};