Creating a jQuery like “$” object

前端 未结 8 1341
伪装坚强ぢ
伪装坚强ぢ 2020-12-08 03:25

My end goal is being able to do something like this:

MyVar(parameter).functionToPerform();

Silly enough, even after reading up on how varia

相关标签:
8条回答
  • 2020-12-08 03:53

    You can pass the 'azerty' value as parameter to MyClass constructor and change the test('azerty').move() to test.move()

    <script type="text/javascript">
        var MyClass = function(context) { 
            this.print = function(){     
                console.log("Printing"); 
            }  
            this.move = function(){     
            console.log(context); 
            return context;
            } 
        };  
        var test = new MyClass('azerty'); 
        test.print(); // Works 
        console.log('Moving: ' + test.move() ); // Type property error 
    </script>
    
    0 讨论(0)
  • 2020-12-08 03:54

    As I write this, Squeegy's answer has the highest number of votes: 7. Yet it is wrong because __proto__ is non-standard and is not supported by Internet Explorer (even version 8). However, getting rid of __proto__ does not get it working either in IE 6.

    This (somewhat simplified) is the way jQuery actually does it (even try it on IE 6), and it also includes examples of static methods and method chaining. For all the details of how jQuery does it, of course, you will have to check the jQuery source code yourself.

    var MyClass = function(context) {
        // Call the constructor
        return new MyClass.init(context);
    };
    
    // Static methods
    MyClass.init = function(context) {
        // Save the context
        this.context = context;
    };
    MyClass.messageBox = function(str) {
        alert(str);
    };
    
    
    // Instance methods
    MyClass.init.prototype.print = function() {
        return "Printing";
    };
    MyClass.init.prototype.move = function() {
        return this.context;
    };
    
    // Method chaining example
    MyClass.init.prototype.flash = function() {
        document.body.style.backgroundColor = '#ffc';
        setInterval(function() {
            document.body.style.backgroundColor = '';
        }, 5000);
        return this;
    };
    
    
    $('#output').append('<li>print(): '+ MyClass().print() +'</li>');
    $('#output').append('<li>flash().move():'+ MyClass('azerty').flash().move() +'</li>');
    $('#output').append('<li>context: '+ MyClass('azerty').context +'</li>');
    MyClass.messageBox('Hello, world!');
    

    Note that if you need "private" data, you will have to put instance methods inside MyClass.init (with a variable declared just inside that function) as this.print = function() { ... }; instead of using MyClass.init.prototype.

    0 讨论(0)
  • 2020-12-08 03:55

    [Probably] The Most Elegant Solution

    First off, jQuery uses a pattern which is closer to a Monad, a Factory, or a combination of both. Nevertheless, here's what I've been using in my projects because the pattern, itself, is so loosely coupled to whatever class you'd like to utilize:

    ;(function (undefined) {
        if (undefined) return;
        var ENV = this;
    
        var Class = function Class() {
            var thus = this;
    
            function find(data) {
                console.log('@find #data', data);
                return this;
            }
    
            function show(data) {
                console.log('@show #data', data);
                return this;
            }
    
            // export precepts
            this.find = find;
            this.show = show;
    
            return this;
        };
    
        var Namespace = ENV['N'] = new (function Namespace(Class) {
            var thus = this;
    
            var Ns = Class.apply(function Ns(data) {
    
                if (this instanceof N) {
                  return new Namespace(Class);
                }
    
                return Ns.find.apply(Ns, arguments);
            });
    
    
            return Ns;
        })(Class);
    
    }).call(window || new function Scope() {});
    
    var n = N('#id').show(450);
    var m = new N();
    
    m('#id')('.curried').show('slow');
    
    console.log(n !== m);  // >> true
    

    Basically, you can use it as a function, an object, and use the new keyword to construct another unique object/function. You can use this to enforce an arbiter method (default, like the find method above), or use different methods based upon what parameters are input. For instance, you can do something like:

    var elementsList = N('#id1')('#id2')('#otherSpecialElement').each(fn);
    

    -- OR --

    var general = N('.things');
    var specific = general('.specific')('[data-more-specific]').show();
    

    The above would, for instance, accumulate a nodelist of multiple elements (1st expression), or drill down to one specific element (2nd).

    Hope this helps

    0 讨论(0)
  • 2020-12-08 03:56

    The solutions provided so far don't seem to reflect jQuery's exact structure (or jQuery changed over time).

    I recently wanted to create an object (similar to jQuery) and came across this question. So here's my answer:

    // dummy text element 
    var p = document.createElement("p");
    p.innerText = "Lorem ipsum...";
    
    
    // jQuery-like object
    var CustomObject = function (element) {
        return new CustomObject.prototype.init(element);
    };
    
    // constructor
    CustomObject.prototype.init = function (element) {
        this.el = element;
        this.text = element.innerText;
    };
    
    // instance methods
    CustomObject.prototype.log = function () {
        console.log(this.text);
        // by returning "this" at the end of instance methods
        // we make these methods chainable
        return this;
    };
    
    CustomObject.prototype.add2body = function (delay) {
        document.body.appendChild(this.el);
        return this;
    };
    
    // all the instance methods are added to CustomObject, not to CustomObject.init (constructor)
    // calling CustomObject() returns a CustomObject.init object, not CustomObject object
    // so by default, instance methods are not accessible
    // to fix this, you need to assign the prototype of CustomObject to CustomObject.prototype.init
    CustomObject.prototype.init.prototype = CustomObject.prototype;
    
    // testing
    var obj = CustomObject(p).add2body().log();

    0 讨论(0)
  • 2020-12-08 03:57

    jQuery() is both a module with global methods, and a constructor. It automatically calls a constructor if it needs to. If we are not called with a new keyword, then this will not have been constructed with MyClass. We can detect that and call the function in constructor mode instead. Once we do that, then this will be an instance of MyClass and we can start adding stuff to it.

    var MyClass = function(context) {
        // if the function is called without being called as a constructor,
        // then call as a constructor for us.
        if (this.__proto__.constructor !== MyClass) {
            return new MyClass(context);
        }
    
        // Save the context
        this.context = context;
    
        // methods...
        this.print = function() {
            return "Printing";
        }
    
        this.move = function() {
            return this.context;
        }
    };
    
    $('#output').append('<li>print(): '+ MyClass().print() +'</li>');
    $('#output').append('<li>move():'+ MyClass('azerty').move() +'</li>');
    $('#output').append('<li>context: '+ MyClass('azerty').context +'</li>');
    

    http://jsfiddle.net/rvvBr/1/

    0 讨论(0)
  • 2020-12-08 04:12

    when you do

    var test = new MyClass()
    

    you create an object that has two attributes move and print. You object test is no more a function because of the new statement. So calling test() is wrong.

    0 讨论(0)
提交回复
热议问题