参考: https://www.itranslater.com/qa/details/2325714161562551296

是否可以将模板字符串创建为常用字符串

let a="b:${b}";

然后将其转换为模板字符串

let b=10;
console.log(a.template());//b:10

没有eval,2249649119959581696和其他动态代码生成方法?

KOLANICH asked 2019-07-10T10:54:59Z
16个解决方案
59 votes

由于您的模板字符串必须动态(在运行时)中引用eval变量,因此答案是:否,如果没有动态代码生成,则无法做到。

但是使用eval它非常简单:

let tpl = eval('`'+a+'`');
alexpods answered 2019-07-10T10:55:21Z
32 votes

在我的项目中,我使用ES6创建了类似的东西:

String.prototype.interpolate = function(params) {
const names = Object.keys(params);
const vals = Object.values(params);
return new Function(...names, `return \`${this}\`;`)(...vals);
} const template = 'Example text: ${text}';
const result = template.interpolate({
text: 'Foo Boo'
});
console.log(result);

UPDATE我已经删除了lodash依赖项,ES6具有获取键和值的等效方法。

Mateusz Moska answered 2019-07-10T10:56:12Z
29 votes

你在这里要求的是什么:

//non working code quoted from the question
let b=10;
console.log(a.template());//b:10

eval()完全等效(就功率和呃安全性而言):获取包含代码的字符串并执行该代码的能力; 以及执行代码在调用者环境中查看局部变量的能力。

在JS中没有办法让函数在其调用者中看到局部变量,除非该函数是eval().即使Function()也不能这样做。


当你听到那些名为"模板字符串" 谈到JavaScript,我们很自然地认为它是内置的模板库,比如Mustache。 它不是。 它主要是JS的字符串插值和多行字符串。 不过,我认为这将是一个常见的误解。:(

Jason Orendorff answered 2019-07-10T10:57:10Z
25 votes

不,没有动态代码生成,没有办法做到这一点。

但是,我创建了一个函数,它将常规字符串转换为一个函数,该函数可以在内部使用模板字符串提供值的映射。

生成模板字符串Gist

/**
* Produces a function which uses template strings to do simple interpolation from objects.
*
* Usage:
* var makeMeKing = generateTemplateString('${name} is now the king of ${country}!');
*
* console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
* // Logs 'Bryan is now the king of Scotland!'
*/
var generateTemplateString = (function(){
var cache = {}; function generateTemplate(template){
var fn = cache[template]; if (!fn){
// Replace ${expressions} (etc) with ${map.expressions}. var sanitized = template
.replace(/\$\{([\s]*[^;\s\{]+[\s]*)\}/g, function(_, match){
return `\$\{map.${match.trim()}\}`;
})
// Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
.replace(/(\$\{(?!map\.)[^}]+\})/g, ''); fn = Function('map', `return \`${sanitized}\``);
} return fn;
} return generateTemplate;
})();

用法:

var kingMaker = generateTemplateString('${name} is king!');

console.log(kingMaker({name: 'Bryan'}));
// Logs 'Bryan is king!' to the console.

希望这有助于某人。 如果您发现代码有问题,请更新Gist。

Bryan Rayner answered 2019-07-10T10:58:09Z
8 votes

TLDR:[https://jsfiddle.net/w3jx07vt/]

每个人似乎都担心访问变量,为什么不通过它们呢? 我确定在调用者中获取变量上下文并将其传递下去并不会太难。 使用此[https://stackoverflow.com/a/6394168/6563504]从obj获取道具。 我现在无法为你测试,但这应该有效。

function renderString(str,obj){
return str.replace(/\$\{(.+?)\}/g,(match,p1)=>{return index(obj,p1)})
}

测试。 这是完整的代码。

function index(obj,is,value) {
if (typeof is == 'string')
is=is.split('.');
if (is.length==1 && value!==undefined)
return obj[is[0]] = value;
else if (is.length==0)
return obj;
else
return index(obj[is[0]],is.slice(1), value);
} function renderString(str,obj){
return str.replace(/\$\{.+?\}/g,(match)=>{return index(obj,match)})
} renderString('abc${a}asdas',{a:23,b:44}) //abc23asdas
renderString('abc${a.c}asdas',{a:{c:22,d:55},b:44}) //abc22asdas
M3D answered 2019-07-10T10:58:57Z
7 votes

这里的问题是拥有一个可以访问其调用者变量的函数。 这就是我们看到直接eval用于模板处理的原因。 一种可能的解决方案是生成一个函数,该函数采用由字典属性命名的形式参数,并以相同的顺序使用相应的值调用它。 另一种方法是让事情变得简单:

var name = "John Smith";
var message = "Hello, my name is ${name}";
console.log(new Function('return `' + message + '`;')());

对于使用Babel编译器的任何人,我们需要创建闭包,它会记住创建它的环境:

console.log(new Function('name', 'return `' + message + '`;')(name));
didinko answered 2019-07-10T10:59:36Z
5 votes

例如,您可以使用字符串原型

String.prototype.toTemplate=function(){
return eval('`'+this+'`');
}
//...
var a="b:${b}";
var b=10;
console.log(a.toTemplate());//b:10

但原始问题的答案是没有办法的。

sarkiroka answered 2019-07-10T11:00:18Z
5 votes

类似于丹尼尔的答案(和s.meijer的要点),但更具可读性:

const regex = /\${[^{]+}/g;

export default function interpolate(template, variables, fallback) {
return template.replace(regex, (match) => {
const path = match.slice(2, -1).trim();
return getObjPath(path, variables, fallback);
});
} //get the specified property or nested property of an object
function getObjPath(path, obj, fallback = '') {
return path.split('.').reduce((res, key) => res[key] || fallback, obj);
}

注意:这略微提高了s.meijer的原创性,因为它不匹配像${foo{bar}这样的东西(正则表达式只允许${}内的非大括号字符)。


更新:我被要求使用这个例子,所以你去:

const replacements = {
name: 'Bob',
age: 37
} interpolate('My name is ${name}, and I am ${age}.', replacements)
Matt Browne answered 2019-07-10T11:01:08Z
4 votes

我需要这种方法,支持Internet Explorer。 事实证明,甚至IE11都不支持后退。 也; 使用eval或它的等同物Function并不是对的感觉。

对于注意到的人; 我也使用反引号,但是像babel这样的编译器会删除这些反引号。 其他方法建议的方法在运行时依赖于它们。 如前所述; 这是IE11及更低版本中的一个问题。

所以这就是我提出的:

function get(path, obj, fb = `$\{${path}}`) {
return path.split('.').reduce((res, key) => res[key] || fb, obj);
} function parseTpl(template, map, fallback) {
return template.replace(/\$\{.+?}/g, (match) => {
const path = match.substr(2, match.length - 3).trim();
return get(path, map, fallback);
});
}

输出示例:

const data = { person: { name: 'John', age: 18 } };

parseTpl('Hi ${person.name} (${person.age})', data);
// output: Hi John (18) parseTpl('Hello ${person.name} from ${person.city}', data);
// output: Hello John from ${person.city} parseTpl('Hello ${person.name} from ${person.city}', data, '-');
// output: Hello John from -
s.meijer answered 2019-07-10T11:01:54Z
3 votes

我目前无法对现有答案发表评论,因此我无法直接评论Bryan Raynor的出色回应。 因此,这种反应将通过稍微修正来更新他的答案。

简而言之,他的功能实际上无法缓存创建的函数,因此它总是会重新创建,无论它之前是否看过模板。 这是更正后的代码:

    /**
* Produces a function which uses template strings to do simple interpolation from objects.
*
* Usage:
* var makeMeKing = generateTemplateString('${name} is now the king of ${country}!');
*
* console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
* // Logs 'Bryan is now the king of Scotland!'
*/
var generateTemplateString = (function(){
var cache = {}; function generateTemplate(template){
var fn = cache[template]; if (!fn){
// Replace ${expressions} (etc) with ${map.expressions}. var sanitized = template
.replace(/\$\{([\s]*[^;\s\{]+[\s]*)\}/g, function(_, match){
return `\$\{map.${match.trim()}\}`;
})
// Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
.replace(/(\$\{(?!map\.)[^}]+\})/g, ''); fn = cache[template] = Function('map', `return \`${sanitized}\``);
} return fn;
}; return generateTemplate;
})();
user2501097 answered 2019-07-10T11:02:36Z
2 votes

我喜欢s.meijer的回答,并根据他自己的版本编写了自己的版本:

function parseTemplate(template, map, fallback) {
return template.replace(/\$\{[^}]+\}/g, (match) =>
match
.slice(2, -1)
.trim()
.split(".")
.reduce(
(searchObject, key) => searchObject[key] || fallback || match,
map
)
);
}
Daniel answered 2019-07-10T11:03:14Z
2 votes

@Mateusz Moska,解决方案效果很好,但是当我在React Native(构建模式)中使用它时,它会抛出一个错误:无效的字符'`',虽然它在调试模式下运行时有效。

所以我用正则表达式写下了我自己的解决方案。

String.prototype.interpolate = function(params) {
let template = this
for (let key in params) {
template = template.replace(new RegExp('\\$\\{' + key + '\\}', 'g'), params[key])
}
return template
} const template = 'Example text: ${text}',
result = template.interpolate({
text: 'Foo Boo'
}) console.log(result)

演示:[https://es6console.com/j31pqx1p/]

注意:由于我不知道问题的根本原因,我在react-native repo中提出了一张票,[https://github.com/facebook/react-native/issues/14107,]这样一次 他们能够修复/指导我一样:)

Mohit Pandey answered 2019-07-10T11:04:13Z
2 votes

仍然是动态的,但似乎比使用裸eval更受控制:

const vm = require('vm')
const moment = require('moment') let template = '### ${context.hours_worked[0].value} \n Hours worked \n #### ${Math.abs(context.hours_worked_avg_diff[0].value)}% ${fns.gt0(context.hours_worked_avg_diff[0].value, "more", "less")} than usual on ${fns.getDOW(new Date())}'
let context = {
hours_worked:[{value:10}],
hours_worked_avg_diff:[{value:10}], } function getDOW(now) {
return moment(now).locale('es').format('dddd')
} function gt0(_in, tVal, fVal) {
return _in >0 ? tVal: fVal
} function templateIt(context, template) {
const script = new vm.Script('`'+template+'`')
return script.runInNewContext({context, fns:{getDOW, gt0 }})
} console.log(templateIt(context, template))

[https://repl.it/IdVt/3]

Robert Moskal answered 2019-07-10T11:04:56Z
0 votes

此解决方案无需ES6即可运行:

function render(template, opts) {
return new Function(
'return new Function (' + Object.keys(opts).reduce((args, arg) => args += '\'' + arg + '\',', '') + '\'return `' + template.replace(/(^|[^\\])'/g, '$1\\\'') + '`;\'' +
').apply(null, ' + JSON.stringify(Object.keys(opts).reduce((vals, key) => vals.push(opts[key]) && vals, [])) + ');'
)();
} render("hello ${ name }", {name:'mo'}); // "hello mo"

注意:始终在全局范围中创建Function构造函数,这可能会导致全局变量被模板覆盖,例如,render("hello ${ someGlobalVar = 'some new value' }", {name:'mo'});

cruzanmo answered 2019-07-10T11:05:38Z
0 votes

因为我们正在重新发明一些可能是javascript中可爱功能的东西。

我使用eval(),这不安全,但javascript不安全。 我很乐意承认我在javascript方面并不出色,但我有需要,我需要一个答案,所以我做了一个。

我选择使用@{{variable}}而不是/\@\{\{(.*?)(?!\@\{\{)\}\}/g来设置我的变量的样式,特别是因为我想使用文字的多行特征而不进行评估直到它准备就绪。 所以变量语法是@{OptionalObject.OptionalObjectN.VARIABLE_NAME}

我不是javascript专家,所以我很乐意接受改进方面的建议,但......

var prsLiteral, prsRegex = /\@\{(.*?)(?!\@\{)\}/g
for(i = 0; i < myResultSet.length; i++) {
prsLiteral = rt.replace(prsRegex,function (match,varname) {
return eval(varname + "[" + i + "]");
// you could instead use return eval(varname) if you're not looping.
})
console.log(prsLiteral);
}

一个非常简单的实现如下

@{{variable}}

在我的实际实现中,我选择使用@{{variable}}.还有一组大括号。 绝对不可能意外地遇到这种情况。 正则表达式看起来像/\@\{\{(.*?)(?!\@\{\{)\}\}/g

使这更容易阅读

\@\{\{    # opening sequence, @{{ literally.
(.*?) # capturing the variable name
# ^ captures only until it reaches the closing sequence
(?! # negative lookahead, making sure the following
# ^ pattern is not found ahead of the current character
\@\{\{ # same as opening sequence, if you change that, change this
)
\}\} # closing sequence.

如果你没有正则表达式的经验,一个非常安全的规则是逃避每个非字母数字字符,并且不会不必要地逃避字母,因为许多转义字母几乎对所有正则表达式都有特殊含义。

Regular Joe answered 2019-07-10T11:07:18Z
0 votes

你应该尝试使用来自github的Andrea Giammarchi这个小型JS模块:[https://github.com/WebReflection/backtick-template]

/*! (C) 2017 Andrea Giammarchi - MIT Style License */
function template(fn, $str, $object) {'use strict';
var
stringify = JSON.stringify,
hasTransformer = typeof fn === 'function',
str = hasTransformer ? $str : fn,
object = hasTransformer ? $object : $str,
i = 0, length = str.length,
strings = i < length ? [] : ['""'],
values = hasTransformer ? [] : strings,
open, close, counter
;
while (i < length) {
open = str.indexOf('${', i);
if (-1 < open) {
strings.push(stringify(str.slice(i, open)));
open += 2;
close = open;
counter = 1;
while (close < length) {
switch (str.charAt(close++)) {
case '}': counter -= 1; break;
case '{': counter += 1; break;
}
if (counter < 1) {
values.push('(' + str.slice(open, close - 1) + ')');
break;
}
}
i = close;
} else {
strings.push(stringify(str.slice(i)));
i = length;
}
}
if (hasTransformer) {
str = 'function' + (Math.random() * 1e5 | 0);
if (strings.length === values.length) strings.push('""');
strings = [
str,
'with(this)return ' + str + '([' + strings + ']' + (
values.length ? (',' + values.join(',')) : ''
) + ')'
];
} else {
strings = ['with(this)return ' + strings.join('+')];
}
return Function.apply(null, strings).apply(
object,
hasTransformer ? [fn] : []
);
} template.asMethod = function (fn, object) {'use strict';
return typeof fn === 'function' ?
template(fn, this, object) :
template(this, fn);
};

演示(以下所有测试都返回true):

const info = 'template';
// just string
`some ${info}` === template('some ${info}', {info}); // passing through a transformer
transform `some ${info}` === template(transform, 'some ${info}', {info}); // using it as String method
String.prototype.template = template.asMethod; `some ${info}` === 'some ${info}'.template({info}); transform `some ${info}` === 'some ${info}'.template(transform, {info});

javascript - 将字符串转换为模板字符串的更多相关文章

  1. Python Cookbook(第3版)中文版:15.15 C字符串转换为Python字符串

    15.15 C字符串转换为Python字符串¶ 问题¶ 怎样将C中的字符串转换为Python字节或一个字符串对象? 解决方案¶ C字符串使用一对 char * 和 int 来表示, 你需要决定字符串到 ...

  2. 将ASCII字符串转换为UNICODE字符串

    写在前面的话:在MFC的网络编程中,由于现在项目都是使用UNICODE编码,但是网络API的许多函数却只能接受const char*的参数,所以经常会遇到需要将char*转换为TCHAR*的时候,有一 ...

  3. ES6学习----let、const、解构赋值、新增字符串、模板字符串、Symbol类型、Proxy、Set

    这篇es6的学习笔记来自于表哥 表严肃,是我遇到过的讲课最通透,英文发音最好听的老师,想一起听课就去这里吧 https://biaoyansu.com/i/hzhj1206 ES6就是JS6,JS的第 ...

  4. ES5-ES6-ES7_字符串扩展—模板字符串

    includes(), startsWith(), endsWith() 传统上,JavaScript只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中.ES6又提供了三种新方法 ...

  5. es6新语法系列,查找字符串,模板字符串

    一.模板字符串: ES6引入了一种新型的字符串字面量语法,我们称之为模板字符串(template strings).除了使用反撇号字符 ` 代替普通字符串的引号 ' 或 " 外,它们看起来与 ...

  6. C# 将普通字符串转换为二进制字符串

    1.因为项目的需要,在向数据库中添加人的信息时,必须要求是英文或数字,所以想了个办法,将我们人能看懂的字符串编译成二进制字符串转入就行了. 具体的逻辑实现代码如下:

  7. ES6中的模板字符串和新XSS Payload

    ES6中的模板字符串和新XSS Payload 众所周知,在XSS的实战对抗中,由于防守方经常会采用各种各样严格的过滤手段来过滤输入,所以我们使用的XSS Payload也会根据实际情况作出各种各样的 ...

  8. 中文字符串转换为十六进制Unicode编码字符串

    package my.unicode; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Uni ...

  9. Python中 字符串 转换为 字典

    需求:把以下字符串转换为字典 #字符串 testStr = '{ "pName": "Ceshi", "gender": 1, " ...

随机推荐

  1. Pytorch的模型加速方法:Dataparallel (DP) 和 DataparallelDistributedparallel (DDP)

    Dataparallel 和 DataparallelDistributed 的区别 一.Dataparallel(DP) 1.1 Dartaparallel 的使用方式 Dataparallel 的 ...

  2. 小哈学Python ----XML

    XML XML是实现不同语言或程序之间进行数据交换的协议,XML文件格式如下: <data> <country name="Liechtenstein"> ...

  3. MAC系统如果碰到报错信息:sudo:command not found

    ** 一般要考虑最近是否有别人或者自己修改过环境变量,这种报错往往是因为环境变量设置错误导致的. ** 1. 首先要获得创建,或者是打开bash_profile的权限,请在命令行中输入: export ...

  4. C语言:赋值

    #include <stdio.h> //=赋值运算符 //具有方向性,只能将赋值号右边的表达式的值给左边的变量 //赋值语句具有计算功能,赋值号右边可以是常量,变量或表达式都可以 //赋 ...

  5. 【012】JavaSE面试题(十二):多线程(2)

    第一期:Java面试 - 100题,梳理各大网站优秀面试题.大家可以跟着我一起来刷刷Java理论知识 [012] - JavaSE面试题(十二):多线程(2) 第1问:多线程的创建方式? 方式一:继承 ...

  6. flutter实战demo,仿luckin coffee。

    flutter_luckin_coffee flutter luckin coffee application(仿瑞幸咖啡) 目录 前言 安卓扫码体验 flutter版本信息 安装 相关插件 维护者 ...

  7. 【LeetCode】1248. 统计「优美子数组」

    1248. 统计「优美子数组」 知识点:数组:前缀和: 题目描述 给你一个整数数组 nums 和一个整数 k. 如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」. ...

  8. 达梦数据库(DM8)大规模并行集群MPP 2节点安装部署

    达梦数据库大规模并行集群MPP 2节点安装部署   1.环境准备   os 数据库版本 ip mpp角色 centos7.x86 DM8 192.168.30.100 mpp1 centos7.x86 ...

  9. springMVC-2-MVC初步了解

    Spring MVC的特点 轻量级,简单易学 高效 , 基于请求响应的MVC框架 与Spring兼容性好,无缝结合 约定优于配置 功能强大:RESTful.数据验证.格式化.本地化.主题等 简洁灵活 ...

  10. js里的发布订阅模式及vue里的事件订阅实现

    发布订阅模式(观察者模式) 发布订阅模式的定义:它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布订阅模式在JS中最常见的就是DOM的事件绑定与触发 ...