简体   繁体   中英

Writing OO Javascript with jQuery

I come from a Prototype JS background where OO Javascript is encouraged through the use of Class.create() . Now I am doing some JQuery work and I am trying to write some properly structured JQuery code where I can, for example, call the same object function from two different click event handlers.

Here is the code in Prototype:

document.observe("dom:loaded", function() {

    // create document
    APP.pageHelper = new APP.PageHelper();


});

// namespace our code
window.APP = {};

// my class
APP.PageHelper = Class.create({

  // automatically called
  initialize: function(name, sound) {
    this.myValue = "Foo";

    // attach event handlers, binding to 'this' object
    $("myButton").observe("click", this.displayMessage.bind(this))

  },

  displayMessage: function() {
    console.log("My value: " + this.myValue); // 'this' is the object not the clicked button!
  }

});

I am wondering how the following code can be replicated in JQuery where there is no way to bind a function call to the object it is called in, and 'this' is always the element clicked.

I have heard of a way to do it the Douglas Crockford 'module' pattern (http://www.yuiblog.com/blog/2007/06/12/module-pattern/) but I would love if someone could show me how you would implement the code above using JQuery and that pattern.

Thanks in advance.

I roll my own objects based on this good article:

http://www.klauskomenda.com/code/javascript-programming-patterns/

I just choose whichever pattern makes sense for the project I'm working on. So like a quick example to do what you're asking would be:

$.myNamespace.myClass = function (options) {
    this.settings = $.extend({ ... defaults ... }, options);
    this.init();
};
$.myNamespace.myClass.prototype.settings = {
    someValue: 'default',
    someSelector: '#myButton'
};
$.myNamespace.myClass.prototype.init = function () {
    var self = this;
    $(self.settings.someSelector).click(function (event) {
        console.log(self.settings.someValue);
    });
};

You responded below that you knew about prototype but the syntax is a bit annoying. I think that's just a matter of being used to one syntax over another. I'm sure the Prototype library makes use of closures and .prototype just like I did above and like some other answers suggest below. In the end, just write syntax that you feel comfortable with. The suggestion to use Coffee Script is cool too - whatever floats your boat :)

You can absolutely bind an event to something other then the dom element. Just use $.proxy .

Description:

Takes a function and returns a new one that will always have a particular context. version added: 1.4

 /**
  * @param function - The function whose context will be changed.
  * @param context - The object to which the context (this) of the function should be set.
  */
jQuery.proxy( function, context )

This method is most useful for attaching event handlers to an element where the context is pointing back to a different object. Additionally, jQuery makes sure that even if you bind the function returned from jQuery.proxy() it will still unbind the correct function if passed the original.

If you are looking for a somewhat similar OOP structure for JQuery, you might try http://code.google.com/p/jquery-klass/

It's what I use.

You don't need Class.create() to write classes in javascript.

APP.PageHelper = function(name, sound) { // this is the constructor
    this.myValue = "Foo";
    // attach event handlers, binding to 'this' object
    $('#myButton').click($.proxy(this.displayMessage, this)); // use $.proxy instead of `bind`
}
APP.PageHelper.prototype = { // define more prototype functions here
    displayMessage: function() {
        console.log("My value: " + this.myValue); // 'this' is the object not the clicked button!
    }
};

Now for more complicated classes with inheritance I use John Resig's simple class inheritance .

I also separate classes into files, wrapped with a closure. This would be PageHelper.js :

;!!window['APP'] && (function (NS, $) {
    NS.PageHelper = Class.extend({ // see link above
        // functions
        init: function () { // constructor

        },
        displayMessage: function() { 

        }
    });
})(window['APP'], jQuery);

I find writing OO code in CoffeeScript to be much more pleasant than Class.create() or lower level prototype stuff. Check out the section on function binding .

I think the best jQuery Class implementation is from John Resig's blog (http://ejohn.org/blog/simple-javascript-inheritance/). I highly recommend it; it's very similar to Prototype JS.

I wrote a library on top of it to make OO design easy within jQuery ( https://github.com/arturnt/brickjs ). For example, in order to do what you are doing there you can do the following.


Comp.APP = {};
Comp.APP.PageHelper = Comp.extend({
    init: function(e) {
        this._super(e);
        this.myValue = "foo";
    },
    "#myButton click": function() {
        console.log(this.myValue); //prints
    }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM