检测Underscore模板的实例

时间:2013-08-23 19:24:41

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

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

例如:

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中,如果它当前是字符串而不是Underscore模板。

然而,我的2个问题 -

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

如果没有,扩展模板原型链以进行此检查是否过于昂贵?除非它慢得多,否则这似乎是下划线中的(次要)错误。

2 个答案:

答案 0 :(得分:3)

_.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

如果true t来自_.template,那么这两者都应为t()(但反过来,当然不一定如此)。

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

就第二个问题而言,当t instanceof T不是T时,我无法想到Functionvar t = _.template(s); var h = t.exec(...); 如何工作(我可以当然缺少一些显而易见的东西,但是在使用原生类型时通常不能很好地解决这个问题。如果你想说:

t(...)

而不是{{1}}那么它很容易,但它与所有了解Underscore模板的内容不兼容。

答案 1 :(得分:3)

如果你看一下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