【问题标题】:ES6 Template Literals: How to pass a scope before they are interpreted?ES6 模板文字:如何在解释之前传递范围?
【发布时间】:2016-10-25 08:44:58
【问题描述】:

我开始使用模板文字来制作错误生成器。

我有工作代码,但我不得不在constructor 范围内声明可能的错误列表,我对此并不满意。

有没有办法复制模板文字而不对其进行评估,以便我可以在正确的范围内对其进行评估?还是将范围传递给模板文字?

工作error.js:

'use strict';

class Error {
    constructor(code) {
        const error = {
            //...
            //API
            1001: 'No token',
            1002: `${arguments[1]}`,
            1003: `${arguments[1]} ! ${arguments[2]}`,
            1004: 'Missing data'
            //...
        };
        let i = 0;
        this.code = code;
        this.error = error[code];
        //...
    }
}

// export default Error;
module.exports = Error;

调用如下:

'use strict';
const Error = require('./error.js');

console.log(new Error(1002, 'var'));

我想要的是能够在模块范围内声明const error,或者更好的是,在我自己的文件中声明require。但是现在这样做会导致argument 不是constructor 的成员,而是模块的成员。

【问题讨论】:

  • 您可以将模板字符串包装在工厂函数中。
  • 所有这一切要记住的是,如果arguments[1] 是一个字符串,那么对于 "1002: ${arguments[1]}," 根本不需要字符串插值。
  • 这些是模板文字,而不是字符串文字。
  • 关键是模板文字应该用编译器函数包装或重新实现。在这一点上,这个模板语法并不比那里的任何其他 JS 模板引擎更有吸引力。

标签: javascript node.js ecmascript-6


【解决方案1】:

立即计算字符串文字。它们不能用作稍后格式化的模板(不像 Python 的格式字符串看起来很相似)。

您可以按照 Leonid Beschastny 的建议进行操作,并使用为您进行插值的小函数。

类似这样的:

const error = {
    1001: () => 'No token',
    1002: (args) => `${args[1]}`,
    1003: (args) => `${args[1]} ! ${args[2]}`,
    1004: () => 'Missing data'
};
this.error = error[code](arguments);

【讨论】:

  • 更好地使用传播/休息语法。传递arguments 对象效率非常低。
  • @jaap3,我知道有一个实例不会立即评估它们:当它们在函数内部时。看看我下面的答案。
【解决方案2】:

模板字面量不够灵活真是太可惜了。

这里有两种可能接近你想要的方法。

第一:

var s = (item, price) => {return `item: ${item}, price: $${price}`}
s('pants', 10) // 'item: pants, price: $10'
s('shirts', 15) // 'item: shirts, price: $15'

概括:

var s = (<variable names you want>) => {return `<template with those variables>`}

如果你没有运行 E6,你也可以这样做:

var s = function(<variable names you want>){return `<template with those variables>`}

这似乎比之前的答案更简洁一些。

https://repl.it/@abalter/reusable-JS-template-literal

第二

class Person
{

  constructor (first, last)
  {
    this.first = first;
    this.last = last;
  }

  sayName ()
  {
        return `Hi my name is ${this.first} ${this.last}`;
  }
}

var bob = new Person("Bob", "Jones")
console.log(bob.sayName()) // Hi my name is Bob Jones

console.log(new Person("Mary", "Smith").sayName()) // Hi my name is Mary Smith

https://repl.it/@abalter/late-evaluation-of-js-template-literal

【讨论】:

  • 其实这是个好主意!当你有对象时,这比使用模板标签和关联/渲染数组要好得多。更一般地说,你可以简单地做let template = (o) =&gt; `${o.first} ${o.last}` 等等,在任何给定的对象上渲染
【解决方案3】:

我首选的传递范围的解决方案是使用这个包装器:

function defer([fisrt, ...rest]) {
  return (...values) => rest.reduce((acc, str, i) => acc + values[i] + str, fisrt);
}

就是这样。当我想重用模板并推迟替换的解决方案时,我只是这样做:

> t = defer`My template is: ${null} and ${null}`;
> t('simple', 'reusable');          // 'My template is: simple and reusable'
> t('obvious', 'late to the party'; // 'My template is: obvious and late to the party'
> t(null);                          // 'My template is: null and undefined'
>
> defer`Choose: ${'ignore'} / ${undefined}`(true, false); // 'Choose: true / false'

应用这个标签会返回一个'function'(而不是'string'),它会忽略传递给文字的任何参数。然后可以稍后使用新参数调用它。如果某个参数没有对应的替换,则变为'undefined'

您可以在其他答案中找到更多信息:thisthat

【讨论】:

    猜你喜欢
    • 2018-03-08
    • 2019-02-25
    • 2023-03-20
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    相关资源
    最近更新 更多