템플릿 문자열을 일반적인 문자열로 만들 수 있습니까?
let a="b:${b}";
그런 다음 템플릿 문자열로 변환
let b=10;
console.log(a.template());//b:10
않고 eval
, new Function
동적 코드 생성의 다른 수단?
답변
템플릿 문자열은 b
런타임에 변수를 동적으로 참조해야 하므로 대답은 NO입니다. 동적 코드 생성 없이는 불가능합니다.
그러나 eval
그것은 매우 간단합니다.
let tpl = eval('`'+a+'`');
답변
내 프로젝트에서 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);
업데이트
lodash 의존성을 제거했습니다. ES6에는 키와 값을 얻는 동등한 방법이 있습니다.
답변
당신이 요구하는 것 :
//non working code quoted from the question let b=10; console.log(a.template());//b:10
에 (전력, 어, 안전의 측면에서) 정확히 동일하다 eval
: 코드를 포함하는 문자열을 가지고 그 코드를 실행하는 능력; 또한 실행 된 코드가 호출자의 환경에서 로컬 변수를 볼 수있는 기능.
JS에서 함수가 아닌 한 호출자의 로컬 변수를 볼 수있는 방법은 없습니다 eval()
. 심지어 Function()
는 할 수 없습니다.
JavaScript에 “template strings”라는 소리가 들리면 Mustache와 같은 내장 템플릿 라이브러리라고 가정하는 것이 당연합니다. 그렇지 않습니다. 주로 JS의 문자열 보간 및 여러 줄 문자열입니다. 그래도 이것이 한동안 일반적인 오해가 될 것이라고 생각합니다. 🙁
답변
아니요, 동적 코드 생성 없이는이를 수행 할 수있는 방법이 없습니다.
그러나 템플릿 문자열을 내부적으로 사용하여 일반 문자열을 값 맵을 제공 할 수있는 함수로 변환하는 함수를 만들었습니다.
/**
* 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를 업데이트하십시오.
답변
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
답변
여기서 문제는 호출자의 변수에 액세스 할 수있는 함수를 갖는 것입니다. 이것이 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));
답변
여기에 게시 된 좋은 솔루션이 많이 있지만 ES6 String.raw 메소드 를 사용하는 솔루션은 아직 없습니다 . 여기에 나의 설득이 있습니다. 전달 된 객체의 속성 만 허용한다는 점에서 중요한 제한 사항이 있습니다. 즉 템플릿에서 코드 실행이 작동하지 않습니다.
function parseStringTemplate(str, obj) {
let parts = str.split(/\$\{(?!\d)[\wæøåÆØÅ]*\}/);
let args = str.match(/[^{\}]+(?=})/g) || [];
let parameters = args.map(argument => obj[argument] || (obj[argument] === undefined ? "" : obj[argument]));
return String.raw({ raw: parts }, ...parameters);
}
let template = "Hello, ${name}! Are you ${age} years old?";
let values = { name: "John Doe", age: 18 };
parseStringTemplate(template, values);
// output: Hello, John Doe! Are you 18 years old?
- 문자열을 인수가 아닌 텍스트 부분으로 나눕니다. 정규식을 참조하십시오 .
parts: ["Hello, ", "! Are you ", " years old?"]
- 문자열을 속성 이름으로 분할하십시오. 일치하지 않으면 배열을 비 웁니다.
args: ["name", "age"]
obj
특성 이름별로 매개 변수를 맵핑하십시오 . 얕은 한 수준 매핑으로 솔루션이 제한됩니다. 정의되지 않은 값은 빈 문자열로 대체되지만 다른 잘못된 값은 허용됩니다.
parameters: ["John Doe", 18]
- 활용
String.raw(...)
하고 결과를 반환합니다.