使用`_.mixin()`扩展Underscore.js,同时保留原始功能

时间:2014-01-15 16:39:09

标签: javascript backbone.js

我正在使用_.mixin()为Underscore.js中的某些功能添加其他功能。我想要做的是重载调用,以便在使用原始签名时调用原始的Underscore函数。然而,保持对原始函数的引用是非常困难的。我已经尝试了多种方法来保持原始引用只有在_.mixin()将参考点应用于新函数后才能找到。

(function() {
  //Just using the base underscore pattern
  var root = this;

  //Save a object reference to the old function
  var _oldCall = root._.oldCall;
  root._.mixin({
    oldCall: function (list, funk) {
      //Call old function when we detect we should
      if(/*detect old signature*/) return _oldCall(list, funk);

      //Otherwise do something else
      return 'something else';
    }
  });
}).call(this)

最终发生的事情是,当调用进入无限循环时抛出异常,并在堆栈不再推送函数调用时结束。如何替换旧函数的引用?

修改

根据提交的答案,我为@Simon Boudrias建立了一个概念验证。一个只有一个克隆。另一个我试图用克隆替换_的值。第一个例子按预期工作,第二个例子让我大吃一惊,但是当我试图保留一个未经修改的参考时,我正在看到它。

Copy _, extend _, revert _ from copy

var c = _.clone(_);

c.max(); //-Infinity
_.max()) //-Infinity

_.mixin({'max': function () {return 'whole bunches';}});

c.max(); //-Infinity
_.max(); //'whole bunches'

_ = c;

c.max(); //-Infinity
_.max(); //-Infinity

Backup Underscore, copy underscore and assign _ the copy, extend _, then restore _ from backup

var backup = _;
var c = _.clone(_);
_ = c;

backup.max(); // -Infinity
_.max(); // -Infinity

_.mixin({'max': function () {return 'whole bunches';}};

backup.max(); // 'whole bunches'
_.max(); // -Infinity

_ = backup;

backup.max(); // 'whole bunches'
_.max(); // 'whole bunches'

2 个答案:

答案 0 :(得分:1)

从我看到的,代码似乎没问题。唯一的问题是你应该确保在调用旧方法时保留上下文:_oldCall.call(root._, list, funk)

但是,如果方法是递归的(这似乎就是这种情况),这可能会带来奇怪的行为。

这就是为什么修改和不拥有对象通常是个坏主意的原因之一。

为了达到类似的效果,我相信你应该提供一个外观。要么是完整的下划线API,要么只是你要修改的方法。

var raw_ = root._;
var my_ = _.clone(root._); // Consider this pseudo code, I don't think _ clone deeply

my_.myOverride = function() {
    // call the raw_ methods when necessary here
};

// Then export your underscore with your usual module system or global
export._ = my_;
// root.my_ = my_

或者只需制作自己的方法并在必要时导入:

exports = function() {
    // my functions with call to _
}

答案 1 :(得分:1)

我测试了您的代码http://jsfiddle.net/WLCcd/,并显示原始引用已保留,因此在其他位置查找错误

(function() {
  //Just using the base underscore pattern
  var root = this;

    root._.mixin({
    oldCall: function () {
      console.log('old');
    }
    });
  //Save a object reference to the old function

        var _oldCall = root._.oldCall;
    //delete root._.oldCall;
  root._.mixin({
    oldCall: function (list, funk) {
      if(arguments.length == 0) return _oldCall();
 console.log('new');
      //Otherwise do something else
      return 'something else';
    }
  });
    console.dir(_oldCall);
    _.oldCall();
    _.oldCall(1);
}).call(this)