backbone.js 混合每个Underscore方法作为Collection#模型的代理

hc8w905p  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(134)

我正在使用 Backbone.js 库执行以下操作:

var Persons = Backbone.Collection.extend({
    defaults: {
        name: 'unknown',
        age: 18
    },

    over_18: function () {
        return this.filter(function (model) {
            return model.get('age') > 18
        });
    },

    under_18: function () {

        var persons_over_18 = this.over_18;

        return this.without(this, persons_over_18); // it does not work!! why?
    }
});

persons = new Persons([{age: 17}, {age: 27}, {age:31} ]);

persons.under_18().length; // 3 instead of 1

正如你所看到的,方法under_18不能正常工作,因为它返回了所有的模型,而不是只返回年龄属性小于18的模型。
因此,为了调试我的代码,我决定查看Backbone.js注解源代码,特别是以下代码:

var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl', ... ]; // and more

_.each(methods, function(method) {
    Collection.prototype[method] = function() {
      var args = slice.call(arguments);
      args.unshift(this.models);
      return _[method].apply(_, args);
    };
});

但是上面的代码对我来说并不清楚,我仍然不能让第一个工作,因为我希望。
所以我的问题是,我如何修复第一个代码与第二个代码的关系?
下面是我的代码到jsfiddle.net http://jsfiddle.net/tVmTM/176/

mwngjboj

mwngjboj1#

为了更好地理解Backbone.js代码,请给出详细的答案:
在JavaScript中,可以通过两种方式引用对象的“成员”:
1.常用的.符号:foo.say('hello');

  1. [...]表示法,以字符串为参数...有点像关联数组:foo["say"]('hello')
    在Backbone.js中,methods数组中的每个字符串(在此方法上方定义)都被迭代并添加到Collection原型中,因此它被添加到继承(或扩展)Collection的所有类中。
    在函数中,arguments关键字只是引用传入函数的所有参数,即使签名为空:
Collection.prototype[method] = function() { // <- empty signature here!

没有任何参数的切片将把传入的参数转换为数组。请注意这里使用了slice.call(...)(并参考this Stack Overflow question)。

var args = slice.call(arguments);

然后,unshift将Collection模型数组添加到数组的开头。

args.unshift(this.models);

然后我们实际上是在新的参数数组上调用Underscore方法(使用[...]表示法)。使用apply,我们传递_作为第一个参数,它将成为this作用域(更多信息是here

return _[method].apply(_, args);

这允许您执行以下操作:

MyCollection.each(function (model) { ... });

而不是

_.each(MyCollection.models, function (model) { ... });

效果一模一样!前者只会叫后者。:)
为了回答你的问题,你的例子中的问题是_.without方法不接受两个数组,而是接受一个后面跟着一列参数的数组;你正在寻找的方法名为difference(参见this SO question),但它没有Map到Collection中,所以你可以自己Map它(复制Backbone源代码中的代码),或者直接使用它:

return _.difference(this.models, this.over_18());

工作提琴:http://jsfiddle.net/tVmTM/177/
在我看来,最好继续使用filter,就像你对over_18方法所做的那样。更好的是,将over_18under_18作为方法放在Model中(它们所属的地方),然后从集合中使用它们。

uxhixvfz

uxhixvfz2#

1)methods数组中的每个字符串对应于一个下划线方法,如_.forEach_.map_.reduce等。对于methods字符串,Collection原型都会添加一个函数,该函数调用下划线方法,但将集合中的模型作为第一个参数传递,然后是您传入的任何选项。
例如,假设您有一个名为Dogs的集合,其中包含一堆Dog模型。调用Dogs.forEach(options)将调用一个调用_.forEach(Dogs.models, options)的函数。这是一个方便的事情。
2)在第2行,你使用了that,而我认为你是指this。在第3行,在without之后有一个额外的.

相关问题