【问题标题】:Detect instanceof Underscore template检测下划线模板的instanceof
【发布时间】:2013-08-23 19:24:41
【问题描述】:

我希望能够检测我正在查看的对象是否是 _.template 的实例,就像我可以检查主干模型/集合/视图一样。

例如:

var newView = new Backbone.View();
newView instanceof Backbone.View //true

//How I usually use template
var test = _.template("test");
test instanceof _.template //false

//When I would actually expect a successful instanceof check
var test2 = new _.template("test");
test2 instanceof _.template //false

我改用这个:

typeof test == "function"

这对于我的情况基本上已经足够了,因为我只是将我的模板包装在 _.template 中,如果它当前是一个字符串而不是下划线模板。

但是,我的 2 个问题 -

我想知道目前是否有办法检查 instanceof _.template。

如果不是,扩展模板原型链以允许此检查是否过于昂贵?除非它慢得多,否则这似乎是 Underscore 中的一个(小)错误。

【问题讨论】:

    标签: javascript templates backbone.js underscore.js prototypal-inheritance


    【解决方案1】:

    _.template 只是返回一个普通的旧函数,而不是任何特定的实例,也不是你应该与new 一起使用的东西,它只是一个简单的函数。

    如果我们查看the source(我强烈推荐这样的问题),您会发现_.template 的结构或多或少是这样的:

    // A bunch of stuff to convert the template to JavaScript code
    // which is combined with some boiler plate machinery and left
    // in `source`
    // ...
    render = new Function(settings.variable || 'obj', '_', source);
    template = function(data) { return render.call(this, data, _); };
    return template;
    

    所以你从_.template(str) 得到的东西只是一个匿名函数,没有设置特殊的原型链,与instanceof 一起使用的唯一常见的东西是Function。询问t instanceof Function 在这种情况下是否真的不是非常有用,我认为这不会做任何typeof t == 'function' 尚未做的事情。

    但是,_.template will add a source property 到返回的函数:

    source 属性在编译后的模板函数中可用,以便于预编译。

    所以你可以通过将ininstanceoftypeof 结合起来来收紧:

    typeof t === 'function' && 'source' in t
    t instanceof Function  && 'source' in t
    

    如果t 来自_.template,那么两者都应该是true(但反过来当然不一定正确)。

    演示:http://jsfiddle.net/ambiguous/a2auU/

    就第二个问题而言,当T 不是Function 时,我想不出你如何让t()t instanceof T 都工作(我当然可能会遗漏一些明显的东西,但会搞砸原生类型通常在 JavaScript 中效果不佳)。如果你想说:

    var t = _.template(s);
    var h = t.exec(...);
    

    而不是t(...) 那样会很简单,但它会与了解下划线模板的所有内容不兼容。

    【讨论】:

      【解决方案2】:

      如果你查看source of the _.template method,你会发现你在这里叫错了树——下划线不是实例化_.template 对象,它是通过构建一个字符串为你构建一个新函数源代码并使用new Function() 编译它。所以你使用的模板函数是一个新的匿名函数,而不是任何东西的实例。

      如果您真的想要一种识别模板的方法,我建议装饰 _.template 函数以添加某种标志 - 可能作为 constructor 属性:

      var originalMethod = _.template;
      _.template = function() {
          var template = originalMethod.apply(_, arguments);
          template.constructor = _.template;
          return template;
      }
      
      var t = _.template('Foo <%= bar %>');
      t({ bar: "baz" }); // "Foo baz"
      t.constructor === _.template;  // true
      

      【讨论】:

      • constructor 混在一起有多安全/可靠?像template.is_underscore_template 这样的东西可能是一个更好的主意。
      • 好吧,在这种情况下,这根本不重要,而且 OP 似乎想要一些惯用的东西。
      • 不应该重要,但感觉就像用棍子戳一个马蜂窝。
      • 我明白你的意思,但就任何人使用constructor 而言,通常会使用new t.constructor("Foo &lt;%= baz %&gt;") 之类的东西——这在这里可以工作。我想我是在扮演魔鬼的拥护者,因为我实际上不会在我的代码中这样做,但我认为这是非常安全的。 Backbone 所做的事情与设置和重用扩展类的constructor 非常相似。
      • 我可能不会使用它,但它在技术上也可能更接近我所要求的答案。非常感谢你们俩。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多