How does basic object/function chaining work in ja

2019-01-02 15:42发布

I'm trying to get the principles of doing jQuery-style function chaining straight in my head. By this I mean:

var e = f1('test').f2().f3();

I have gotten one example to work, while another doesn't. I'll post those below. I always want to learn the first principle fundamentals of how something works so that I can build on top of it. Up to now, I've only had a cursory and loose understanding of how chaining works and I'm running into bugs that I can't troubleshoot intelligently.

What I know:

  1. Functions have to return themselves, aka "return this;"
  2. Chainable functions must reside in a parent function, aka in jQuery, .css() is a sub method of jQuery(), hence jQuery().css();
  3. The parent function should either return itself or a new instance of itself.

This example worked:

var one = function(num){
    this.oldnum = num;

    this.add = function(){
        this.oldnum++;
        return this;
    }

    if(this instanceof one){
        return this.one;    
    }else{
        return new one(num);    
    }
}
var test = one(1).add().add();

But this one doesn't:

var gmap = function(){

    this.add = function(){
        alert('add');

        return this;    
    }   

    if(this instanceof gmap) {
        return this.gmap;   
    } else{
        return new gmap();  
    }

}
var test = gmap.add();

5条回答
还给你的自由
2楼-- · 2019-01-02 16:11

First, let me state that i am explaining this in my own words.

Method chaining is pretty much calling a method of the object being returned by another function/method. for example (using jquery):

$('#demo');

this jquery function selects and returns a jquery object the DOM element with the id demo. if the element was a text node(element), we could chain on a method of the object that was returned. for example:

$('#demo').text('Some Text');

So, as long as a function/method returns an object, you can chain a method of the returned object to the original statement.

As for why the latter don't work, pay attention to where and when the keyword this is used. It is most likely a context issue. When you are calling this, make sure that this is referring to that function object itself, not the window object/global scope.

Hope that helps.

查看更多
后来的你喜欢了谁
3楼-- · 2019-01-02 16:12

In JavaScript Functions are first class Objects. When you define a function, it is the constructor for that function object. In other words:

var gmap = function() {
    this.add = function() {
        alert('add');
    return this;
    }

    this.del = function() {
       alert('delete');
       return this;
    }

    if (this instanceof gmap) {
        return this.gmap;
    } else {
        return new gmap();
    }
}
var test = new gmap();
test.add().del();

By assigning the

new gmap();
to the variable test you have now constructed a new object that "inherits" all the properties and methods from the gmap() constructor (class). If you run the snippet above you will see an alert for "add" and "delete".

In your examples above, the "this" refers to the window object, unless you wrap the functions in another function or object.

Chaining is difficult for me to understand at first, at least it was for me, but once I understood it, I realized how powerful of a tool it can be.

查看更多
高级女魔头
4楼-- · 2019-01-02 16:14

To "rewrite" a function, but still be able to use the original version, you must first assign the original function to a different variable. Assume an example object:

function MyObject() { };

MyObject.prototype.func1 = function(a, b) { };

To rewrite func1 for chainability, do this:

MyObject.prototype.std_func1 = MyObject.prototype.func1;
MyObject.prototype.func1 = function(a, b) {
    this.std_func1(a, b);
    return this;
};

Here's a working example. You just need to employ this technique on all of the standard objects that you feel need chainability.

By the time you do all of this work, you might realize that there are better ways to accomplish what you're trying to do, like using a library that already has chainability built in. *cough* jQuery *cough*

查看更多
余生请多指教
5楼-- · 2019-01-02 16:36

Just call the method as var test = gmap().add();

as gmap is a function not a variable

查看更多
临风纵饮
6楼-- · 2019-01-02 16:37

Sadly, the direct answer has to be 'no'. Even if you can override the existing methods (which you probably can in many UAs, but I suspect cannot in IE), you'd still be stuck with nasty renames:

HTMLElement.prototype.setAttribute = function(attr) { 
    HTMLElement.prototype.setAttribute(attr) //uh-oh;  
}

The best you could probably get away with is using a different name:

HTMLElement.prototype.setAttr = function(attr) {
    HTMLElement.prototype.setAttribute(attr);
    return this;
}
查看更多
登录 后发表回答