JavaScript中的哪些对象具有.length属性? (又名为什么Underscore _.each将我的函数对象视为数组?)

时间:2013-03-18 23:17:15

标签: javascript underscore.js

我一直认为只有Array个对象具有.length属性。但是,我再次看到提到“阵列式”的对象。我没有调查过这个,现在看来我对JS中这个话题的无知可能会让我陷入困境。一个很好的例子:

我有以下代码:

var View = function(options) {
  // code
};

_.extend(View, Backbone.Events, {

    make_children: function(parent) {
      // code
    }

});

稍后,我将此View Function与Underscore的_.each一起使用,后者决定此函数对象是一个数组,因为它具有.length属性:

// Code from Underscore.js's `_.each`:
} else if (obj.length === +obj.length) { // This is true
  for (var i = 0, l = obj.length; i < l; i++) { // **So, execution goes here**
    if (iterator.call(context, obj[i], i, obj) === breaker) return
  }
} else {
  for (var key in obj) {
    if (_.has(obj, key)) { // **Execution does __not__ go here**
      if (iterator.call(context, obj[key], key, obj) === breaker) return;
    }
  }
}

这导致代码不起作用,因为obj[i]其中i是整数索引,实际上并未在obj View上定义。确切地说,在上面的代码中,obj[0]undefined,而obj.length === +obj.lengthtrueobj.length1。这是怎么回事?

附录

Underscore的首席维护人员在https://github.com/documentcloud/underscore/pull/510上说了以下内容:

  

简单地制作每个拒绝功能对象并没有多大帮助。我们已经   有意识地决定使用数字长度属性来检测   类似数组的对象。

     

相反,不要将函数对象传递给each

附录2

意识到由于我无法将函数对象传递给_.each,我可以将它“强制转换”为常规对象,如下所示:

var regular_obj = _.extend({}, View);

2 个答案:

答案 0 :(得分:5)

  

JavaScript中的哪些对象具有.length属性?

通过如此重复的定义,任何具有length属性的对象。

This happens to include functions.

  

length是函数对象的属性,表示函数期望的参数数量,即形式参数的数量。

这也是类似数组的,因为它有一个length

var foo = {
    bar: true,
    baz: 'quux',
    length: 42
}

答案 1 :(得分:5)

此处的问题是underscore.jsjquery非常相似,都使用.length属性作为其each函数中的标记。当length属性存在时,该函数假定传递的参数可以通过正常的for循环迭代。这个逻辑背后的原因是期望在定义length属性时,可以按顺序迭代参数 ,这就是使用for循环的原因。

误用length的结果本质上是名称冲突,其中存在意外结果。我建议将length更改为另一个同义词,例如sizecapacitytotalViews等。


修改

如果没有其他选择供您使用,并且您必须保留其中的长度,同时仍然保留_.each的功能,那么您可以稍微破解它。此插件适用于下划线版本1.4.3的缩小版本

var s = Array.prototype.ForEach;
var r = {};
var myEach = function (n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length&&typeof(n[0])!="undefined"){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(_.has(n,a)&&t.call(e,n[a],a,n)===r)return};
_.each=myEach;

以下是演示:http://jsfiddle.net/Xa5qq/

基本上,当forEach属性存在但length时,它会使用typeof(yourObject[0]) == "undefined"