从字符串模板中获取通配符名称

Get wildcarnames from string template

有没有一种快速的方法(我的意思是一种已知的方法)从字符串模板中获取通配符名称?例如...

const str = `Hello ${name}, today is ${weekday}!`;
getWildCards(str); // will return ['name', 'weekday']

我正在创建一个翻译工具,translation 函数不会提前知道通配符。

编辑:

实际上,事实证明有一种使用 tagged template literals 从模板文字中提取参数的本机方法,它允许您使用以下形式的函数解析模板文字:

function tag(strings, param1, param2, ..., paramN) { ... }

因此,如果您使用字符串 (${ 'foo' }) 而不是在模板文本 (${ foo }) 的表达式中使用变量,那么如果您这样做:

tag`${ 'a' }${ 'b' } - XXX ${ 'c' }`

strings 将是 ['', '', ' - XXX ', ''],您将收到 3 个参数,其值为 'a''b''c'.

你可以 return 任何你想要的标签函数,所以你的用例的一个很好的解决方案是 return 一对 [paramsList, closure],闭包将是接收一个对象(映射)的函数,其参数在原始字符串文字中使用,并使用它们来构建结果字符串。像这样:

function extractParams(strings, ...args) {
  return [args, dict => {   
    return strings[0] + args
      .map((arg, i) => dict[arg] + strings[i + 1]).join('');
  }];
}

const [params, translate] = extractParams`Hello ${ 'name' }, today is ${ 'weekday' }`;

console.log(params);
console.log(translate({ name: 'Foo', weekday: 'Barday' }));

原始答案:

假设模板字符串被包装到一个函数中,这样它就不会抛出 ReferenceError,并且您稍微更改了模板字符串的格式,以便使用的参数始终是来自对象,您可以为此使用 proxy

假设您有这样的事情:

function getSentence(key, args = {}) {
  // Note that for the proxy solution to work well, you need to wrap each of them
  // individually. Otherwise you will get a list of all the params from all the
  // sentences.

  const sentences = {
      salutation: (args) => `Hello ${ args.name }, today is ${ args.weekday }!`,
      weather: (args) => `Today is ${ args.weather } outside.`,
  };

  return sentences[key](args) || '';
}

function extractParams(key) {
  const params = [];
  
  const proxy = new Proxy({}, {
    get: (target, name) => {
      params.push(name);
    },
  });
  
  getSentence(key, proxy);
  
  return params;
}

console.log(extractParams('salutation'));

无论如何,请注意这仅在您的参数中只有一层深度时才有效,否则您将需要一个代理 return 另一个代理 return 另一个代理...并跟踪路径 (prop.subprop...)。他们还应该 return a function that returns a string for the last 属性 which will be interpolated in the resulting string.

function getSentence(key, args = {}) {
  // Note that for the proxy solution to work well, you need to wrap each of them
  // individually. Otherwise you will get a list of all the params from all the
  // sentences.

  const sentences = {
      salutation: (args) => `Hello ${ args.name }, today is ${ args.a.b.c.d }!`,
      weather: (args) => `Today is ${ args.weather } outside.`,
  };

  return sentences[key](args) || '';
}

function getProxy(params, path = []) {
  return new Proxy({}, {
    get: (target, name) => {
      if (typeof name === 'symbol') {
        params.push(path);
        
        return () => ''; // toString();
      } else {
        return getProxy(params, path.concat(name));
      }
    },
  });
}

function extractParams(key) {
  const params = [];
  
  getSentence(key, getProxy(params));
  
  return params;
}

console.log(extractParams('salutation'));