【问题标题】:How is jQuery object able to behave like an Array, even though it isn't one? [duplicate]jQuery 对象如何能够表现得像一个数组,即使它不是一个? [复制]
【发布时间】:2014-01-12 16:50:22
【问题描述】:

我一直认为 jQuery $ 函数返回一个带有 jQ​​uery 方法的数组。 我想提供一些例子:

假设我们有一个数组

var arr = [1,2,3];

然后我们可以添加我们自己的属性:

arr.someProp = 10;
arr.someMethod = function() { ... }

之后arr 仍然是一个数组,尽管有自定义属性:

arr instanceof Array;   //true

所以,在最近的实验之前,我认为 jQuery 对象类似于 arr(但更复杂)。 我只是运行这段代码:

$('div') instanceof Array;  //false (!!!)

但它的行为就像一个数组。它具有push 方法、length 属性,即使在这种情况下也能正常工作:

var $jq = $('div');
$jq.length; //3
$jq.push(123);  //wrong code, I know, this is just for test
$jq.length      //4

另外,如果你执行console.log($('div')),它会输出如下内容:

[<div></div>, <div></div>, <div></div>]

除了 jQuery 对象还有一些方法是相等的 Array.prototype 方法:

$('div').sort === Array.prototype.sort;     //true
$('div').splice === Array.prototype.splice; //true

我的问题是:这个东西是如何被创造出来的?

所以如果你们能解释一下并提供一些代码示例,我将非常感谢你们。

【问题讨论】:

  • 这是一个函数一个对象同时魔法,但绝不是一个数组!
  • 您可以随时浏览 jQuery 源代码。这有点曲折和令人困惑,但很有教育意义。
  • 仅供参考,ECMAScript specification 明确定义了大多数数组方法来处理 类数组 对象,for examplepush 函数是有意通用的; 它不要求它的this 值是一个Array 对象。因此它可以转移到其他类型的对象中作为方法使用。push 功能是否可以成功应用于宿主对象取决于实现。

标签: javascript jquery arrays prototype


【解决方案1】:

所以,在最近的实验之前,我认为 jQuery 对象类似于 arr(但更复杂)。我只是运行这段代码:

$('div') instanceof Array;  //false (!!!)

但它的行为就像一个数组。它有 push 方法,length 属性,可以正常工作...

只要具有正确的.length 属性和预期的数字索引,任何可变对象都可以像数组一样“表现”内置数组方法。

拿走这个物品:

var obj = {
    "3": "buz",
    "0": "foo",
    "2": "baz",
    "1": "bar",
    length: 4
}

它不是一个数组,但我们可以将Array.prototype.push 方法放在对象上,它就可以正常工作了。

obj.push = Array.prototype.push;

obj.push("hi");

现在obj 将拥有5.length,并将包含"hi" 字符串。

【讨论】:

  • 谢谢你的解释,但我还是不明白jQuery开发者是如何让浏览器输出这个对象为[&lt;div&gt;&lt;/div&gt;, &lt;div&gt;&lt;/div&gt;, &lt;div&gt;&lt;/div&gt;]的?
  • @Zub:控制台开发人员使用一个技巧来确定一个对象是一个数组。我相信他们只是测试指向函数的splice() 属性和.length 属性,如果它们存在,他们会使用数组语法将其打印出来。如果你以我的例子做obj.splice = Array.prototype.splice,你应该得到相同的打印输出。
  • 哇!看来您对splicelength 的看法是正确的。我刚试了一下,它真的在方括号中输出!
  • @Zub:是的,为了清楚起见,这并不能使它成为一个真正的数组。我猜你已经知道这一点,因为你的instanceof 测试。这只是控制台开发人员使用的一种快速破解方法,与语言本身没有任何关系。
【解决方案2】:

jQuery 对象是一个类似数组的对象。它有一些成员与相应的数组成员具有相同的用途。

Javascript 中还有其他类似数组的对象,例如从 document.getElementsByTagName method 返回的对象是 HTMLCollectionNodeList(取决于浏览器),它们有一些来自数组的成员,但没有全部。

您可以创建一个常规对象并添加任何您喜欢的成员,如果有足够多的成员像相应的数组成员一样工作,以便您可以以某种方式将其用作数组,则可以将其称为类数组对象。

例子:

var myArrayLookAlike = {
  length: 0,
  data: [],
  push: function(value){
    this.data.push(value);
    this.length = this.data.length;
  },
  pop: function(){
    var value = this.data.pop(value);
    this.length = this.data.length;
    return value;
  }
};

jQuery 库有makeArray method,可用于从类数组对象创建真正的数组对象,当类数组对象缺少方法需要使用它的某些特定成员时,可以使用该对象。

【讨论】:

    【解决方案3】:

    我的问题是:这个东西是如何被创造出来的?

    作为一个更广泛的介绍,看看这是否有助于理解,几行代码的迷你 jQuery。我已经使用 jQuery 很长时间了,它基本上都归结为一个原型,其中包含 return this 用于链接的方法,以及一些用于处理元素集合的数组助手。 map 是您的“核心方法”,其他所有操作元素的方法都以一种或另一种方式使用map。然后你需要toArrayflattenunique 就可以了。 jQuery 建立在这些基本概念之上,但显然更复杂,但这将使您对使用现代 JavaScript 的 jQuery 等库的内部工作有一个整体了解(例如,checkout Zepto.js):

    var $ = (function(){ // jQuery shortcut
    
      // Helpers to work with collections of elements
    
      // Converts pseudo-arrays to real arrays
      // such as elements queried with native DOM methods
      var toArray = function(x) {
        return Array.prototype.slice.call(x);
      };
      // Flattens array of arrays, one level
      var flatten = function(xs) {
        return Array.prototype.concat.apply([], xs);
      };
      // Remove duplicates
      var unique = function(xs) {
        return xs.filter(function(x, i) {
          return xs.indexOf(x) == i;
        });
      };
      // Query the DOM on the document or an element
      var query = function(sel, el) {
        return toArray((el || document).querySelectorAll(sel));
      };
      // Helper to access object properties with `map`
      var dot = function(s) {
        return function(x) {
          return x[s];
        };
      };
    
      // Constructor
      function jQuery(sel) {
        // Elements queried from the DOM
        // as an array
        this.el = query(sel);
        this.length = this.el.length;
      }
    
      // Public methods that operate on the array
      // of queried elements
      jQuery.prototype = {
        // Return array (collection of elements)
        get: function(idx) {
          return idx == null ? this.el : this.el[idx];
        },
        // Map is the core method,
        // all other methods use `map` in way or the other
        map: function(fn) {
          var f = function(x) {
            var fx = fn.call(this, x);
            // It's a pseudo-array?
            if (fx.length) return toArray(fx);
            return fx;
          };
          this.el = unique(flatten(this.el.map(f)));
          this.length = this.el.length;
          return this; // chain
    
        },
        parent: function() {
          return this.map(dot('parentNode'));
        },
        children: function() {
          return this.map(dot('children'));
        }
      };
    
      // Wrapper around construtor
      // to create new instances without `new`
      return function(sel) {
        return new jQuery(sel);
      };
    }());
    

    【讨论】:

      【解决方案4】:

      这是我用来提交表单的示例,它可以帮助您解决问题。

      JS 代码

       // process the form
              $('.updateClient').click(function(event) {
      
                  // get the form data
                  // there are many ways to get this data using jQuery (you can use the class or id also)
                  var formData = {    
                      'clientbrandid' :$("input[id=editClientBrand]").val()
                  };
      
                  // process the form
                  var ajaxResponse = $.ajax({
                      type: 'POST', // define the type of HTTP verb we want to use (POST for our form)
                      url: 'someURL', // the url where we want to POST
                      data: JSON.stringify( formData ),
                      contentType :'application/json',
                      error: function(data,status,error){
                                  console.log(data+': '+status+': '+error);
                                                  }
                          }).done(function(apiResponse) {
                                  $('.someClass').append('Hello There!'); //This is what creates the <div></div> on the html side and when the function is done it appends the content between those two <div></div>
                          });
      
          });
      

      HTML 端

      ..............Some form code on top of this.
      
          <div class='someClass'></div> <--- this is where the output will show after the code is done
      

      【讨论】:

        猜你喜欢
        • 2010-09-09
        • 1970-01-01
        • 1970-01-01
        • 2021-05-02
        • 2020-04-14
        • 1970-01-01
        • 2012-03-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多