Javascript 推迟ES6模板文本的执行
我正在使用新功能,我想到的第一件事是JavaScript的Javascript 推迟ES6模板文本的执行,javascript,ecmascript-6,template-literals,Javascript,Ecmascript 6,Template Literals,我正在使用新功能,我想到的第一件事是JavaScript的String.format,因此我开始实现一个原型: String.prototype.format = function() { var self = this; arguments.forEach(function(val,idx) { self["p"+idx] = val; }); return this.toString(); }; console.log(`Hello, ${p0}. This is a
String.format
,因此我开始实现一个原型:
String.prototype.format = function() {
var self = this;
arguments.forEach(function(val,idx) {
self["p"+idx] = val;
});
return this.toString();
};
console.log(`Hello, ${p0}. This is a ${p1}`.format("world", "test"));
但是,在将模板文本传递给原型方法之前,会对其进行评估。是否有任何方法可以编写上述代码,将结果延迟到动态创建元素之后?我可以看到三种方法:
- 使用模板字符串,就像它们被设计用来使用一样,不使用任何
函数:格式
甚至功能参数用于实际延迟评估:console.log(`Hello, ${"world"}. This is a ${"test"}`); // might make more sense with variables: var p0 = "world", p1 = "test"; console.log(`Hello, ${p0}. This is a ${p1}`);
const welcome = (p0, p1) => `Hello, ${p0}. This is a ${p1}`; console.log(welcome("world", "test"));
- 不要使用模板字符串,而是使用普通字符串文字:
String.prototype.format = function() { var args = arguments; return this.replace(/\$\{p(\d)\}/g, function(match, id) { return args[id]; }); }; console.log("Hello, ${p0}. This is a ${p1}".format("world", "test"));
- 使用标记的模板文本。请注意,替换仍将在不被处理程序拦截的情况下进行计算,因此如果没有名为so的变量,则不能使用
之类的标识符。如果(更新:未更新),此行为可能会更改p0
函数格式化程序(文本,…替换){ 返回{ 格式:函数(){ var out=[]; for(变量i=0,k=0;i
我也喜欢
String.format
函数的想法,并且能够显式定义解析变量
这就是我想到的。。。基本上是一个字符串。用deepObject
查找替换方法
const isUndefined=o=>typeof o=='undefined'
常量nvl=(o,valueIfUndefined)=>isUndefined(o)?值未定义:o
//给定“路径”,从对象获取深度值。
常量getDeepValue=(对象,路径)=>
路径
.替换(/\[\]\.?/g,“.”)
.split(“.”)
.filter(s=>s)
.减少((acc,val)=>acc和acc[val],obj)
//给定一个字符串,解析所有模板变量。
const resolveTemplate=(str,变量)=>{
返回str.replace(/\$\{([^\}]+)\}/g,(m,g1)=>
nvl(getDeepValue(变量,g1),m))
}
//向字符串原型添加“格式”方法。
String.prototype.format=函数(变量){
返回resolveTemplate(此,变量)
}
//设置解析变量。。。
变量变量={}
变量['top level']='Foo'
变量['deep object']={text:'Bar'}
变量aGlobalVariable='Dog'
//==>Foo Bar Dog Dog${不是一个对象。text}扩展@Bergi的答案,当您意识到可以返回任何结果时,带标签的模板字符串的力量就会显现出来,而不仅仅是普通字符串。在他的示例中,标记构造并返回一个具有闭包和函数属性format
的对象
在我最喜欢的方法中,我自己返回一个函数值,您可以稍后调用它并传递新参数来填充模板。像这样:
function fmt([fisrt, ...rest], ...tags) {
return values => rest.reduce((acc, curr, i) => {
return acc + values[tags[i]] + curr;
}, fisrt);
}
然后构建模板并推迟替换:
> fmt`Test with ${0}, ${1}, ${2} and ${0} again`(['A', 'B', 'C']);
// 'Test with A, B, C and A again'
> template = fmt`Test with ${'foo'}, ${'bar'}, ${'baz'} and ${'foo'} again`
> template({ foo:'FOO', bar:'BAR' })
// 'Test with FOO, BAR, undefined and FOO again'
另一个更接近您所写内容的选项是,返回一个从字符串扩展而来的对象,让duck直接输入并尊重接口。String.prototype
的扩展不起作用,因为以后需要关闭模板标记来解析参数
class FormatString extends String {
// Some other custom extensions that don't need the template closure
}
function fmt([fisrt, ...rest], ...tags) {
const str = new FormatString(rest.reduce((acc, curr, i) => `${acc}\${${tags[i]}}${curr}`, fisrt));
str.format = values => rest.reduce((acc, curr, i) => {
return acc + values[tags[i]] + curr;
}, fisrt);
return str;
}
然后,在呼叫站点中:
> console.log(fmt`Hello, ${0}. This is a ${1}.`.format(["world", "test"]));
// Hello, world. This is a test.
> template = fmt`Hello, ${'foo'}. This is a ${'bar'}.`
> console.log(template)
// { [String: 'Hello, ${foo}. This is a ${bar}.'] format: [Function] }
> console.log(template.format({ foo: true, bar: null }))
// Hello, true. This is a null.
您可以参考。AFAIS中的更多信息和应用程序,有用的功能“字符串模板的延迟执行”仍然不可用。使用lambda是一种表达性、可读性和简短的解决方案,但是:
var greetingTmpl = (...p)=>`Hello, ${p[0]}. This is a ${p[1]}`;
console.log( greetingTmpl("world","test") );
console.log( greetingTmpl("@CodingIntrigue","try") );
您可以使用下面的函数将值注入字符串
let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);
let inject=(str,obj)=>str.replace(/\${(.*?})/g,(x,g)=>obj[g]);
//---测试---
//对象中的参数
让t1='我的名字是${name},我是${age}。我兄弟的名字也是${name};
设r1=注入(t1,{姓名:'JOHN',年龄:23});
log(“对象:”,r1);
//数组中的参数
设t2=“值${0}位于${2}数组中,${1}值为${0}。”
设r2=注入(t2,{…['A,B,C',666,'BIG']});
log(“数组:”,r2)代码>虽然这个问题已经得到了回答,但这里有一个加载配置文件时使用的简单实现(代码是typescript,但很容易转换为JS,只需删除键入):
/**
*这种方法有许多局限性:
*-不接受带有数字或其他符号的变量名(相对容易修复)
*-它不接受任意表达式(很难修复)
*/
函数deferredTemplateLiteral(模板:string,环境:{[key:string]:string | undefined}):string{
常数varsMatcher=/\${([a-zA-Z\]+)}/
常量globalVarsmatcher=/\${[a-zA-Z\]+}/g
const varMatches:string[]=template.match(globalVarsmatcher)??[]
const templateVarNames=varMatches.map(v=>v.match(varsMatcher)?[1]??“”
const templateValues:(字符串|未定义)[]=templateVarNames.map(v=>env[v])
const templateInterpolator=新函数(…[…templateVarNames,`return\`${template}\`;`])
返回templateInterpolator(…templateValues)
}
//用法:
延迟模板文件(“hello${thing},{thing:“world”})==“hello world”
尽管有可能使这些东西更强大、更灵活,但它带来了太多的复杂性和风险,却没有带来太多好处
这里有一个指向要点的链接:(参见上面@Bergi非常类似的回答)
函数插值(字符串,…位置){
var错误=位置。
let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);