【问题标题】:How can jQuery do method chaining? [duplicate]jQuery如何做方法链? [复制]
【发布时间】:2012-02-02 01:00:10
【问题描述】:

可能重复:
how does jquery chaining work?

这是您在 jQuery 代码中看到的正常现象:

$("div.selected").html("Blah.");

因此,在上面的代码中,在函数$() 中,它有一个名为html() 的函数。而我不明白的是,我通常会做的是:

funcA("blah");  //normal function, cool.
funcA.funcB("blah");  //normal function in an object, still cool.

现在这令人困惑:

funcA("blah").funcB("blah")  //huh??

funcB 怎么知道funcA 中的参数?
jQuery 是如何做到这一点的?

谢谢。

【问题讨论】:

标签: javascript jquery


【解决方案1】:
//function returning an object is a possibility. bar has access to elem because of
// the shared scope
function foo ( elem ) {
    return {
        bar : function () {
            return elem.id;
        }
    };
}

在这个中,foo 函数返回一个对象,其中包含您想要的任何方法。因此,当您拨打foo 时,您会收到以下信息:

{
    bar : function () {
        return elem.id;
    }
}

elem 在您致电foo 时出现。如果您要在bar 的顶部添加console.log( elem ),您会发现它与您传递给foo 的内容相同。

//this is kinda how jQuery does it:
var foo = (function() {
    function foo ( elem ) {
        this.elem = elem;
    }

    foo.prototype.bar = function () {
        return this.elem.id;
    };

    return function ( elem ) {
        return new foo( elem );
    };
}());

这个稍微复杂一点,实际上一分为二。

function foo ( elem ) {
    this.elem = elem;
}

foo.prototype.bar = function () {
    return this.elem.id;
};

谁不喜欢与经典继承名称混合的原型继承?无论如何...函数既可以作为常规函数,也可以作为构造函数。这意味着,当使用 new 关键字调用时,会发生两件特殊的事情:

  1. this 内部的foo 指的是新制作的foo.prototype 的副本
  2. foo.prototype 被返回(除非foo 返回一个对象)

请注意,foo.prototype 不是一个神奇的值。它就像任何其他对象属性一样。

所以,在foo 函数/构造函数中,我们只是设置foo.prototype.elem,而不是直接设置。可以这样想(有点不准确,但可以):foo.prototype 是产品的蓝图。每当您想制作更多时,就使用蓝图-复制里面的东西,然后传递。在foo 内部,this 指的是蓝图的这种复制。

但是,通过显式设置 foo.prototype 的值,我们正在更改蓝图本身。每当调用 foo 时,都会使用这个更改后的蓝图调用它。

最后,一旦foo 完成,复制(复制的蓝图,但在foo 完成后)被返回。此复制包含原始蓝图以及我们可能添加的所有其他内容 - 在此示例中为 elem

var foo = (function() {
    ...
    return function ( elem ) {
        return new foo( elem );
    };
}());

我们创建一个无名函数并立即执行它。

(function () {
    console.log( 'meep' );
}());

//is the equivalent of:
var something = function () {
    console.log( 'meep' );
};
something();
something = undefined; //we can no longer use it

//and of this
function () {
    console.log( 'meep' );
}(); //<--notice the parens
//however, it's considered good practice to wrap these self-executing-anonymous-functions
// in parens

像所有其他函数一样,它们可以返回值。并且这些值可以被捕获到变量中。

var answer = (function () {
    return 42;
}());
answer ==== 42;

var counter = (function () {
    var c = 0;
    return function () {
        return c++;
    };
}());
//counter is now a function, as a function was returned
counter(); //0
counter(); //1
counter(); //2...

所以:

var foo = (function () {
    ...
    return function ( elem ) {
        ...
    };
}());

返回一个接收参数的函数,该函数现在分配给foo

函数内部:

return new foo( elem );

是为了确保我在上面谈到的特殊条件 - 它通过明确执行new 操作来确保制造蓝图的新副本。这实际上可以像这样复制:

function foo ( elem ) {
    this.elem = elem;
}
foo.prototype.bar = function () {...};

只要您总是使用 new 关键字调用 foo

【讨论】:

  • 你的例子其实更让我困惑,我不知道为什么它真的有效......
  • @Derek 编辑答案以包含所有解释
  • 我和德里克在一起;这很令人困惑,太长了,没有提到链接。虽然投反对票似乎有点矫枉过正,但确实似乎可以大大加强,并包括一些链接。
  • 很好的答案!
【解决方案2】:

当您执行funcA("blah").funcB("blah") 时,无论funcA 返回什么都会调用funcB。所以你有funcA 返回一些具有funcB 的对象,然后调用它。

对于 jQuery,大多数 jQuery 函数都返回 jQuery 对象,因此函数调用可以任意链接。许多 jQuery 函数旨在修改返回的 jQuery 对象的内容。因此,在您的示例中,对html() 的调用并非“知道”传递给$() 函数的内容。相反,$() 函数返回一个 jQuery 对象,该对象指向与给定选择器匹配的 DOM 元素。然后,进一步调用该 jQuery 对象上的函数将影响那些选定的元素。

【讨论】:

    【解决方案3】:

    jquery 中的大多数函数都返回一个包含一组元素的 jquery 对象。 html 并不确切知道$() 的参数,更多的是$() 的结果有一组元素,这些元素是根据传递给$() 的参数创建的。

    funcAfuncB 的示例中,您可以轻松地让funcA 返回一个对象,该对象具有一个名为funcB 的函数。该对象还可以包含传递给funcA 的值,然后对funcB 的调用也可以“知道”该值。

    http://jsfiddle.net/ScENm/

    【讨论】:

      【解决方案4】:
      function funcA(arg1) {
      
          var enclosedVariable= arg1;
      
          return {
             funcB: function () {
                alert(enclosedVariable);
             }
          };
      }
      

      这是一个快速而肮脏的例子。 ^^

      funcA 接受一个参数并保存它,然后返回一个包含单个函数的对象。它已被“封闭”,现在funcB 可以访问它。

      从技术上讲,您甚至不必保存它...arg1 也可用于funcB

      【讨论】:

        【解决方案5】:

        您应该研究链接,这就是您所描述的。你可以谷歌"jQuery chaining" 开始。另请查看jQuery's pluging tutorial 了解更多信息

        【讨论】:

          【解决方案6】:

          函数没有什么特别的,你可以在对象中返回一个函数。举个简单的例子:

          function $() {
              return {
                  html: function() {
                  }
              };
          }
          
          $().html(); // You just called the function!
          

          jQuery 没有什么特别之处。当你在 jQuery 中调用一个不返回值的函数时,它通常会返回调用它的 jQuery 对象,如下所示:

          var obj = {
              doSomething: function() {
                  return this;
              },
              doSomethingElse: function() {
                  alert('Hi!');
              }
          };
          
          obj.doSomething().doSomethingElse(); // Alerts "Hi!"
          

          因为,它只是一个对象。

          【讨论】:

          • 那么,html() 怎么知道传递给$() 的是什么?
          • @Derek:选择器存储在对象内部。 Kind of like this.
          • @Derek:我修改了我的答案来回应这个问题;简而言之,html() 不知道传递给$() 的内容,但是对$() 的调用会生成一个包含适当DOM 元素的jQuery 对象(由传入的选择器过滤)。然后,html() 调用作用于该 jQuery 对象,从而影响这些特定元素。
          • @JacobM:也许你应该通知 Derek,而不是我 :)
          【解决方案7】:

          链接通常是根据方法应该返回的对象来完成的。如果object Aclass A 的实例并且其中的方法返回object A,则返回的对象可以再次应用于同一个类,并且可以以链接方式排列。或者说class A的对象返回class B的对象,那么返回的对象可以应用到class B的方法中。

          objectOfA->methodOfA(arg)->methodOfB(args);
          

          在这种情况下,如果objectOfA-&gt;methodOfA(arg) 返回class B 的对象,则可以调用class B 的方法并像上面那样链接。

          在你的情况下,

          $('div.selected').html('Blah ..')
          

          这里$('div.selected')返回一个jquery元素对象(或对象数组);可以应用 .html() 方法,因为该方法仅适用于 jquery 的元素对象。它只是像其他编程语言一样链接。

          如果是 PHP,这种情况看起来像,

          $class->method1(argument)->method(2) 
          

          在这种情况下,如果类 A 有两个方法 method1 和 method2 并且 method1 返回它自己的实例,那么方法 2 再次适用于它。

          这也可以与函数相关。让我们假设我有这样的功能;

          def function1(name):
              return name
          
          def function2(arg):
              print len(name)
          

          现在,这两个函数可以简单地链接为,

          function2(function1('My Name is blah ...'))
          

          由于 function1 返回一个值,该值的类型必须与 function2 的输入参数匹配,这就是对象的工作方式。

          【讨论】:

            猜你喜欢
            • 2013-11-10
            • 1970-01-01
            • 2015-09-19
            • 2011-11-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多