【问题标题】:Javascript: always execute function in execution contextJavascript:始终在执行上下文中执行函数
【发布时间】:2014-01-20 01:06:44
【问题描述】:

我写了这个快速模板函数:

var templatize = function(string) {
    return function (string) {
      return string.replace(/{{(.*?)}}/g, function(pattern, match) {
        value = this[match];
        if (value) {
          return value;
        } else {
          return pattern;
        }
      });
    }.call(this, string);
}

这是做什么的:

var foo = "bar", bar = "foo";
templatize("We are {{foo}} and {{bar}}, but not {{crazy}}"); // "We are bar and foo but not {{crazy}}"

我对此很满意,只是我遇到了范围界定问题。当然,templatize 方法可以通过命名作用域访问,但是,templatize 的当前执行上下文无法在我的函数中自动访问。

调用$.proxy(templatize, this)("We are {{foo}} and {{bar}}, but not {{crazy}}") 之类的方法应该可以,对吧?

但我想在不需要调用 $.proxy() 的情况下实现这一点(最好不使用任何 jQuery),以便上下文自动转移到执行。

我正在为.call().apply() 和其他关闭而苦苦挣扎,但我想我在互联网的某个地方读到它是可能的。谢谢

【问题讨论】:

标签: javascript scope closures


【解决方案1】:

为什么不传递一个包含视图变量的对象?会更干净,然后可能在您的视图中显示任何现有变量。

var templatize = function(string, variables) {
  return function (string) {
    return string.replace(/{{(.*?)}}/g, function(pattern, match) {
      value = variables[match];
      if (value) {
        return value;
      } else {
        return pattern;
      }
    });
  }.call(this, string);
}

【讨论】:

  • 最后,这就是我最终要做的。谢谢!
  • @AugustinRiedinger 你可以删除这个包装函数:return function (string) {...}.call(this, string);,它什么都不做。
  • @AugustinRiedinger 然后可以将替换函数中的六行替换为一行:return variables[match] || pattern;,意思是“值或模式”。
【解决方案2】:

你可以避免使用 jQuery 这样做:

var templatize = function(string) {
    var me = this; // the data source
    return string.replace(/{{(.*?)}}/g, function (full, key) {
        // "this" refers to the string itself
        return me[key] || full;
    });
}

如果您想使用jQuery.proxy(),请包装替换功能:

var templatize = function(string) {
    return string.replace(/{{(.*?)}}/g, jQuery.proxy(function (full, key) {
        // "this" now refers permanently to the data source
        return this[key] || full;
    }, this));
}

在这两种情况下,您都可以使用call 将数据源绑定到this

templatize.call({ hello: 'Hi!' }, '{{hello}}');

走得更远

您可以通过编译模板进行优化:

function compile(tpl) {
    var i = -1, tmp = [];
    tpl = tpl.split(/{{([^{}]+)}}/);
    while (++i < tpl.length) {
        if (i % 2) tmp.push('this["' + tpl[i] + '"]');
        else if (tpl[i]) tmp.push('"' + tpl[i].replace(/"/g, '\\"') + '"');
    }
    return new Function(
        'return [' + tmp.join() + '].join("");'
    );
}

使用示例:

var tpl = compile('{{hello}} {{hello}}');
tpl.call({ hello: 'Hi!' }); // "Hi! Hi!"
tpl.call({ hello: 'Yo!' }); // "Yo! Yo!"

关于上面的例子,这里是compile返回的函数:

function () {
    return [this["hello"]," ",this["hello"]].join("");
}

请注意,您也可以使用数组:

var tpl = compile('{{1}} {{0}}');
tpl.call(['a', 'b']); // "b a"

性能测试:http://jsperf.com/template-compiling.

【讨论】:

    最近更新 更多