ES6 टेम्पलेट शाब्दिक रनटाइम (या पुन: उपयोग) पर प्रतिस्थापित किया जा सकता है?


129

tl? dr: क्या पुन: प्रयोज्य टेम्पलेट को शाब्दिक बनाना संभव है?

मैं टेम्पलेट शाब्दिक का उपयोग करने की कोशिश कर रहा हूं, लेकिन मुझे लगता है कि मुझे अभी नहीं मिला है और अब मैं निराश हो रहा हूं। मेरा मतलब है, मुझे लगता है कि मैं इसे प्राप्त करता हूं, लेकिन "यह" यह नहीं होना चाहिए कि यह कैसे काम करता है, या इसे कैसे प्राप्त करना चाहिए। इसे अलग तरह से मिलना चाहिए।

मेरे द्वारा देखे गए सभी उदाहरणों (यहां तक ​​कि टेम्प्लेट किए गए टेम्प्लेट) के लिए यह आवश्यक है कि "प्रतिस्थापन" को घोषणा के समय किया जाए और समय न चलाया जाए, जो टेम्प्लेट के लिए मेरे लिए बिल्कुल बेकार लगता है। शायद मैं पागल हूं, लेकिन मेरे लिए एक "टेम्पलेट" एक दस्तावेज है जिसमें टोकन शामिल हैं जो इसका उपयोग करने पर प्रतिस्थापित हो जाते हैं, न कि जब आप इसे बनाते हैं, अन्यथा यह सिर्फ एक दस्तावेज (यानी, एक स्ट्रिंग) है। एक टोकन को टोकन के रूप में टोकन के साथ संग्रहीत किया जाता है और जब आप मूल्यांकन करते हैं तो उन टोकन का मूल्यांकन किया जाता है।

हर कोई समान उदाहरण देता है:

var a = 'asd';
return `Worthless ${a}!`

यह अच्छा है, लेकिन अगर मुझे पहले से पता है a, तो मैं सिर्फ return 'Worthless asd'या return 'Worthless '+a। क्या बात है? गंभीरता से। ठीक है बिंदु आलस्य है; कम प्लस, अधिक पठनीयता। महान। लेकिन यह एक टेम्पलेट नहीं है! IMHO नहीं। और MHO सब मायने रखता है! समस्या, IMHO, यह है कि टेम्पलेट का मूल्यांकन तब किया जाता है जब वह घोषित की जाती है, इसलिए, यदि आप करते हैं, तो IMHO:

var tpl = `My ${expletive} template`;
function go() { return tpl; }
go(); // SPACE-TIME ENDS!

चूंकि expletiveघोषित नहीं किया गया है, यह कुछ इस तरह का उत्पादन करता है My undefined template। उत्तम। असल में, क्रोम में कम से कम, मैं टेम्पलेट भी घोषित नहीं कर सकता; यह एक त्रुटि फेंकता है क्योंकि expletiveपरिभाषित नहीं है। टेम्प्लेट घोषित करने के बाद मुझे प्रतिस्थापन करने में सक्षम होने के लिए क्या चाहिए:

var tpl = `My ${expletive} template`;
function go() { return tpl; }
var expletive = 'great';
go(); // My great template

हालाँकि, मैं नहीं देखता कि यह कैसे संभव है, क्योंकि ये वास्तव में टेम्पलेट नहीं हैं। यहां तक ​​कि जब आप कहते हैं कि मुझे टैग का उपयोग करना चाहिए, नहीं, वे काम नहीं करते हैं:

> explete = function(a,b) { console.log(a); console.log(b); }
< function (a,b) { console.log(a); console.log(b); }
> var tpl = explete`My ${expletive} template`
< VM2323:2 Uncaught ReferenceError: expletive is not defined...

यह सब मुझे विश्वास दिलाता है कि टेम्पलेट शाब्दिक रूप से गलत तरीके से लिखे गए हैं और उन्हें बुलाया जाना चाहिए कि वे वास्तव में क्या हैं: heredocs । मुझे लगता है कि "शाब्दिक" भाग को मुझे छोड़ देना चाहिए था (जैसा कि अपरिवर्तनीय है)?

क्या मैं कुछ भूल रहा हूँ? क्या पुन: प्रयोज्य टेम्पलेट को शाब्दिक बनाने का एक (अच्छा) तरीका है?


मैं तुम्हें देता हूं, पुन: प्रयोज्य टेम्पलेट शाब्दिक :

> function out(t) { console.log(eval(t)); }
  var template = `\`This is
  my \${expletive} reusable
  template!\``;
  out(template);
  var expletive = 'curious';
  out(template);
  var expletive = 'AMAZING';
  out(template);
< This is
  my undefined reusable
  template!
  This is
  my curious reusable
  template!
  This is
  my AMAZING reusable
  template!

और यहाँ एक भोले "सहायक" समारोह है ...

function t(t) { return '`'+t.replace('{','${')+'`'; }
var template = t(`This is
my {expletive} reusable
template!`);

... इसे "बेहतर" बनाने के लिए।

मैं उन्हें उस क्षेत्र की वजह से टेम्पलेट जाइटर कहलाने के लिए इच्छुक हूं, जहां से वे गंदी भावनाओं का उत्पादन करते हैं।


1
यह स्ट्राइकथ्रू का समर्थन करता है (लेकिन इस तरह की टिप्पणियों में नहीं)। अपना पाठ एक <strike>टैग में रखें ।
पॉइन्टी

ES6 टेम्पलेट शाब्दिक ज्यादातर पुराने जमाने के स्ट्रिंग इंटरपोलेशन के लिए हैं। यदि आप चाहते हैं कि डायनामिक टेम्प्लेट हैंडलबार आदि का उपयोग करें, या पॉइंटी के टैग किए गए टेम्प्लेट समाधान।
जॉज़


8
क्या आप कृपया अपनी पोस्ट को थोड़ा कम बना सकते हैं? इसके अलावा, ऐसा लगता है कि आपने Q & A प्रारूप में एक ट्यूटोरियल लिखना चाहा है, यदि आपने ऐसा किया है, तो कृपया अपने प्रश्न से " मैं आपको देता हूं ... " भाग को हटा दें और उत्तर के रूप में पोस्ट करें
बरगी

मैंने देखा कि यहाँ कई अच्छे उत्तर हैं। शायद एक को स्वीकार करें।
अबाल्टर

जवाबों:


86

इन शाब्दिक अन्य टेम्पलेट इंजनों की तरह काम करने के लिए एक मध्यस्थ रूप होना चाहिए।

इसका सबसे अच्छा तरीका Functionकंस्ट्रक्टर का उपयोग करना है ।

const templateString = "Hello ${this.name}!";
const templateVars = {
    name: "world"    
}

const fillTemplate = function(templateString, templateVars){
    return new Function("return `"+templateString +"`;").call(templateVars);
}

console.log(fillTemplate(templateString, templateVars));

अन्य टेम्प्लेट इंजनों की तरह आप उस स्ट्रिंग को फ़ाइल जैसी अन्य जगहों से प्राप्त कर सकते हैं।

इस पद्धति का उपयोग करके समस्याएँ हो सकती हैं जैसे टेम्प्लेट टैग का उपयोग करना कठिन है, लेकिन यदि आप चतुर हैं, तो उन्हें जोड़ा जा सकता है। देर से प्रक्षेप के कारण आपके पास इनलाइन जावास्क्रिप्ट तर्क भी नहीं हो सकता है। यह भी कुछ सोचा के साथ remedied किया जा सकता है।


8
अच्छा! आप भी उपयोग कर सकते हैंnew Function(`return \`${template}\`;`)
रुबेन स्टोक

और इन टेम्प्लेट को एक विधि पर कॉल करके, या किसी अन्य टेम्प्लेट के संकलित परिणाम में पारित करके, तर्कों के माध्यम से "शामिल" किया जा सकता है।
क्वेंटिन एंगेल्स

क्वेंटिन 'नो टेम्प्लेट टैग' का क्या अर्थ है? धन्यवाद!
मिकमेकाना

10
सावधान रहें कि यह टेम्पलेट स्ट्रिंग ट्रांसप्लिकेशन (यानी वेबपैक) के लिए 'छिपा' है और इस तरह क्लाइंट-साइड पर पर्याप्त रूप से संगत (यानी IE11) में ट्रांसपाइल नहीं करेगा ...!
फ्रैंक नोके

9
XSS भेद्यता ? इस
Kamil Kiełczewski

65

आप एक समारोह में एक टेम्पलेट स्ट्रिंग डाल सकते हैं:

function reusable(a, b) {
  return `a is ${a} and b is ${b}`;
}

टैग किए गए टेम्प्लेट से आप यही काम कर सकते हैं:

function reusable(strings) {
  return function(... vals) {
    return strings.map(function(s, i) {
      return `${s}${vals[i] || ""}`;
    }).join("");
  };
}

var tagged = reusable`a is ${0} and b is ${1}`; // dummy "parameters"
console.log(tagged("hello", "world"));
// prints "a is hello b is world"
console.log(tagged("mars", "jupiter"));
// prints "a is mars b is jupiter"

यह विचार है कि टेम्प्लेट पार्सर को वैरिएबल "स्लॉट्स" से निरंतर स्ट्रिंग्स को विभाजित करने दिया जाए, और फिर एक फ़ंक्शन लौटाया जाए जो इसे हर बार मानों के एक नए सेट के आधार पर एक साथ वापस करता है।


3
@FelixKling जो हो सकता है; मैं जाँच करूँगा और ठीक करूँगा यदि ऐसा है तो। संपादित करें हां ऐसा लगता है कि मैंने उदाहरण का एक महत्वपूर्ण हिस्सा छोड़ दिया है, जो कि "पुन: प्रयोज्य" फ़ंक्शन है :)
Pointy

@FelixKling मुझे यकीन नहीं है कि मुझे क्या करना चाहिए क्योंकि मैं उस समय को याद नहीं कर सकता जो मैं सोच रहा था!
नुकीले

1
हाँ, यह खास मतलब यह नहीं है कि या तो tbh होने के लिए;) तुम हमेशा इसे हटा सकते हैं .... लेकिन reusableइतना है कि यह एक फ़ंक्शन को लागू किया जा सकता है, और आप का उपयोग करेंगे ${0}और ${1}बजाय शाब्दिक अंदर ${a}और ${b}। तब आप फ़ंक्शन के तर्कों को संदर्भित करने के लिए उस मान का उपयोग कर सकते हैं, जो बर्गी अपने आखिरी उदाहरण में करता है: stackoverflow.com/a/22619256/218196 (या मुझे लगता है कि यह मूल रूप से समान है)।
फेलिक्स क्लिंग

1
@FelixKling ठीक है मुझे लगता है कि मैं ओपी की तर्ज पर कम से कम अस्पष्ट है।
16:25 पर पॉंच

3
टैग किए गए टेम्पलेट वास्तव में शक्तिशाली हो सकते हैं यदि परिणाम वास्तव में एक स्ट्रिंग नहीं है। मेरी एक परियोजना में उदाहरण के लिए, मैं इसका उपयोग एएसटी नोड इंटरपोलेशन करने के लिए करता हूं। उदाहरण के expression`a + ${node}`लिए, एक मौजूदा एएसटी नोड के साथ एक बाइनरी एक्सप्रेशन नोड का निर्माण कर सकता है node। आंतरिक रूप से हम मान्य कोड उत्पन्न करने के लिए एक प्लेसहोल्डर सम्मिलित करते हैं, इसे एएसटी के रूप में पार्स करते हैं और प्लेसहोल्डर को मूल्य में पारित होने के साथ बदलते हैं।
फेलिक्स क्लिंग

45

संभवतः ऐसा करने का सबसे साफ तरीका तीर के कार्यों के साथ है (क्योंकि इस बिंदु पर, हम पहले से ही ES6 का उपयोग कर रहे हैं)

var reusable = () => `This ${object} was created by ${creator}`;

var object = "template string", creator = "a function";
console.log (reusable()); // "This template string was created by a function"

object = "example", creator = "me";
console.log (reusable()); // "This example was created by me"

... और टैग किए गए टेम्पलेट शाब्दिक के लिए:

reusable = () => myTag`The ${noun} go ${verb} and `;

var noun = "wheels on the bus", verb = "round";
var myTag = function (strings, noun, verb) {
    return strings[0] + noun + strings[1] + verb + strings[2] + verb;
};
console.log (reusable()); // "The wheels on the bus go round and round"

noun = "racecars", verb = "fast";
myTag = function (strings, noun, verb) {
    return strings[0] + noun + strings[1] + verb;
};
console.log (reusable()); // "The racecars go fast"

यह भी उपयोग से बचा जाता है eval()या Function()जो संकलक के साथ समस्याएं पैदा कर सकता है और बहुत मंदी का कारण बन सकता है।


मुझे लगता है कि यह सबसे अच्छा है क्योंकि आप myTagकुछ सामान करने के लिए फ़ंक्शन के अंदर कुछ कोड इंजेक्ट कर सकते हैं । उदाहरण के लिए, आउटपुट को कैश करने के लिए कुंजी के रूप में इनपुट परम का उपयोग करें।
वाह

मुझे लगता है कि यह सबसे अच्छा जवाब है। आप तीर फ़ंक्शन में पैरामीटर भी जोड़ सकते हैं जो मुझे लगता है कि यह भी क्लीनर बनाता है var reusable = (value: string) => `Value is ${value}`:।
हैगिसैंडचिप्स

13

2019 उत्तर :

नोट : लाइब्रेरी ने मूल रूप से उपयोगकर्ताओं से XSS से बचने के लिए तार की सफाई करने की अपेक्षा की थी। लाइब्रेरी के संस्करण 2 को अब evalपूरी तरह से परहेज करने के लिए उपयोगकर्ता स्ट्रिंग्स को सैनिटाइज़ (जो वेब डेवलपर्स को वैसे भी करना चाहिए) की आवश्यकता नहीं है ।

es6-dynamic-templateNPM पर मॉड्यूल करता है।

const fillTemplate = require('es6-dynamic-template');

वर्तमान उत्तरों के विपरीत:

  • यह ES6 टेम्पलेट स्ट्रिंग्स का उपयोग करता है, समान प्रारूप का नहीं। अपडेट संस्करण 2, उपयोगकर्ताओं को असंगत इनपुट स्ट्रिंग्स का उपयोग करने से रोकने के लिए ES6 टेम्पलेट स्ट्रिंग्स के बजाय एक समान प्रारूप का उपयोग करता है।
  • यह thisटेम्पलेट स्ट्रिंग में की जरूरत नहीं है
  • आप किसी एक फ़ंक्शन में टेम्पलेट स्ट्रिंग और चर निर्दिष्ट कर सकते हैं
  • यह StackOverflow से कोपिस्टा के बजाय एक अनुरक्षित, अद्यतन योग्य मॉड्यूल है

उपयोग सरल है। टेम्प्लेट स्ट्रिंग को बाद में हल किया जाएगा क्योंकि एकल उद्धरण का उपयोग करें!

const greeting = fillTemplate('Hi ${firstName}', {firstName: 'Joe'});

यदि आप इसे रिएक्ट नेटिव के साथ उपयोग कर रहे हैं तो यह विशेष रूप से एंड्रॉइड पर टूट जाएगा। एंड्रॉइड नोड रनटाइम डायनामिक टेम्प्लेट का समर्थन नहीं करता है, केवल प्रीफ़िल्ड वाले
ओलिवर डिक्सन

1
यह एक समाधान है जिसका उपयोग मैं अपनी व्यक्तिगत परियोजनाओं में करता हूं और यह त्रुटिपूर्ण रूप से काम करता है। मुझे वास्तव में लगता है कि इस तरह की छोटी उपयोगिताओं के लिए बहुत सारे पुस्तकालयों का उपयोग करना एक बुरा विचार है।
ओलिवर डिक्सन

1
XSS भेद्यता ? विवरण इस
कामिल Kiełczewski 14

1
@kamil केवल XSS यदि आप a) उपयोगकर्ताओं को b बनाने की क्षमता देते हैं) इनपुट स्ट्रिंग्स को साफ नहीं करते हैं। मैं एक चेतावनी जोड़ूंगा कि लोगों को हालांकि उपयोगकर्ता इनपुट को पवित्र करना चाहिए।
मिकमेकाना

1
यह es6 टेम्पलेट शाब्दिक रूप से दूरस्थ रूप से उपयोग नहीं करता है। कोशिश करें 10 * 20 = ${10 * 20}तो यह एक समान प्रारूप हो सकता है, लेकिन यह दूरस्थ रूप से es6 टेम्पलेट शाब्दिक भी नहीं है
gman

12

हाँ, आप इसे अपने स्ट्रिंग के साथ जेएस Function(या eval) के रूप में टेम्पलेट के साथ पार्स करके कर सकते हैं - लेकिन यह अनुशंसित नहीं है और एक्सएसएस हमले की अनुमति दें

इसके बजाय आप सुरक्षित तरीके से ऑब्जेक्ट objफ़ील्ड को strगतिशील तरीके से टेम्पलेट में सम्मिलित कर सकते हैं

let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);


यह मेरे द्वारा उपयोग की जाने वाली विधि है और यह अच्छी तरह से काम करती है। अच्छा उदाहरण! करता है? RegEx में मदद के बाद *? मैं एक RegEx विशेषज्ञ नहीं हूं, लेकिन मैं अनुमान लगा रहा हूं कि * का मतलब शून्य या अधिक है (और आप इस मामले में "अधिक" चाहते हैं), लालची प्रतिबंध की कोई आवश्यकता नहीं है?
Gen1-1

@ Gen1-1 का .*?मतलब गैर-लालची है - यदि आप हटाते हैं "?"तो स्निपेट गलत परिणाम देगा
कामिल कील्वेज़ेस्की

तुम सही हो, मेरी गलती है। मैं अपने टेम्पलेट्स में $ का उपयोग नहीं करता हूं, और RegEx: / {(\ w * *)} / g का उपयोग करता हूं क्योंकि मेरे पास टैग में रिक्त स्थान कभी नहीं है, लेकिन *? भी काम करता है। मैं उपयोग करता हूँ:function taggedTemplate(template, data, matcher) { if (!template || !data) { return template; } matcher = matcher || /{(\w*)}/g; // {one or more alphanumeric characters with no spaces} return template.replace(matcher, function (match, key) { var value; try { value = data[key] } catch (e) { // } return value || ""; }); }
Gen1-1

@ Gen1-1 भी संभव डेटा निहित है? जैसे data = { a: 1, b: { c:2, d:3 } }-> b.c?
मूसचा

1
@muescha आप पंक्ति को बदल देंगे: मान = डेटा [कुंजी], पुनरावृत्ति का उपयोग करने के लिए और अपनी संपूर्ण डेटा ऑब्जेक्ट और नेस्टेड ऑब्जेक्ट को तब तक खोजें जब तक आपको संपत्ति नहीं मिली। उदाहरण: codereview.stackexchange.com/questions/73714/… , और mikedoesweb.com/2016/es6-depth-first-object-tree-search
Gen1-1

9

@Metamorphasi द्वारा प्रदान किए गए उत्तर को सरल बनाना;

const fillTemplate = function(templateString, templateVars){
  var func = new Function(...Object.keys(templateVars),  "return `"+templateString +"`;")
  return func(...Object.values(templateVars));
}

// Sample
var hosting = "overview/id/d:${Id}";
var domain = {Id:1234, User:22};
var result = fillTemplate(hosting, domain);

console.log(result);


यह कोड अग्रणी उत्तर की तुलना में अधिक आत्म-व्याख्यात्मक है। समझ गए मेरे ऊपर वोट :)
ymz

यह आपको चरों या बाहरी फ़ाइलों (NodeJS में) का उपयोग करने की अनुमति देता है क्योंकि टेम्पलेट या गतिशील रूप से रन-टाइम पर उनका निर्माण करते हैं। के उपयोग के बिना eval
b01

XSS भेद्यता ? दुर्भावनापूर्ण कोड (वैरिएबल var hosting) के साथ यहाँ Fiddle ।
Kamil Kiełczewski

7

आप आदेश दिया पैरामीटर या संदर्भ / नामस्थान उपयोग करने के लिए अपने टेम्पलेट, में चर संदर्भित करने के लिए नहीं करना चाहते हैं जैसे ${0}, ${this.something}, या ${data.something}, आप एक टेम्पलेट समारोह है कि आप के लिए scoping का ख्याल रखता है हो सकता है।

आप इस तरह के खाके को कैसे बुला सकते हैं इसका उदाहरण :

const tempGreet = Template(() => `
  <span>Hello, ${name}!</span>
`);
tempGreet({name: 'Brian'}); // returns "<span>Hello, Brian!</span>"

खाका समारोह:

function Template(cb) {
  return function(data) {
    const dataKeys = [];
    const dataVals = [];
    for (let key in data) {
      dataKeys.push(key);
      dataVals.push(data[key]);
    }
    let func = new Function(...dataKeys, 'return (' + cb + ')();');
    return func(...dataVals);
  }
}

इस मामले में क्वर्की है कि आपको केवल एक फ़ंक्शन (उदाहरण में मैंने एक तीर फ़ंक्शन का उपयोग किया है) पास करना है जो ES6 टेम्पलेट शाब्दिक रिटर्न देता है। मुझे लगता है कि हम जिस तरह के पुन: प्रयोज्य प्रक्षेप प्राप्त कर रहे हैं, उसे प्राप्त करने के लिए यह एक मामूली व्यापार है।

यहाँ यह GitHub पर है: https://github.com/Adelphos/ES6-Rususeable-Template


3
यह अच्छा है, लेकिन न्यूनतमकरण (वीएलएस, फंक, आदि) अनावश्यक है, 'सीबी' एक कॉलबैक नहीं है (यह पूरी तरह से सिंक कोड है), और आप बस इस्तेमाल कर सकते हैं Object.values()औरObject.keys()
मिक्मेकाना

3

संक्षिप्त उत्तर बस लॉस्ट में _.template का उपयोग करना है

// Use the ES template literal delimiter as an "interpolate" delimiter.
// Disable support by replacing the "interpolate" delimiter.
var compiled = _.template('hello ${ user }!');
compiled({ 'user': 'pebbles' });
// => 'hello pebbles!'

3

क्या मैं कुछ भूल रहा हूँ? क्या पुन: प्रयोज्य टेम्पलेट को शाब्दिक बनाने का एक [अच्छा] तरीका है?

शायद मुझे कुछ याद आ रहा है, क्योंकि इस मुद्दे का मेरा समाधान मुझे इतना स्पष्ट लगता है कि मैं बहुत आश्चर्यचकित हूं कि किसी ने पहले से ही इस तरह के पुराने प्रश्न को नहीं लिखा है।

मेरे पास इसके लिए लगभग एक-लाइनर है:

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

बस इतना ही। जब मैं एक टेम्पलेट का पुन: उपयोग करना चाहता हूं और सबस्टेशनों के समाधान को टालना चाहता हूं, तो मैं बस यही करता हूं:

> 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'


विस्तारित उत्तर

यह सरल कोड कार्यात्मक है, लेकिन यदि आपको अधिक विस्तृत व्यवहार की आवश्यकता है, तो वही तर्क लागू किया जा सकता है और अनंत संभावनाएं हैं। आप ऐसा कर सकते हैं:

  1. मूल मापदंडों का उपयोग करें:

आप निर्माण में शाब्दिक रूप से पारित मूल मूल्यों को संग्रहीत कर सकते हैं और टेम्पलेट को लागू करते समय रचनात्मक तरीकों से उनका उपयोग कर सकते हैं। वे झंडे बन सकते हैं, सत्यापनकर्ता, कार्य आदि टाइप कर सकते हैं। यह एक उदाहरण है जो उन्हें डिफ़ॉल्ट मान के रूप में उपयोग करता है:

    function deferWithDefaults([first, ...rest], ...defaults) {
      return (...values) => rest.reduce((acc, curr, i) => {
        return acc + (i < values.length ? values[i] : defaults[i]) + curr;
      }, first);
    }

फिर:

    > t = deferWithDefaults`My template is: ${'extendable'} and ${'versatile'}`;
    > t('awesome');                 // 'My template is: awesome and versatile' 
  1. एक टेम्पलेट कारखाना लिखें:

इस तर्क को उस फ़ंक्शन में लपेट कर करें जो अपेक्षा करता है, तर्क के रूप में, एक कस्टम फ़ंक्शन जिसे कमी में लागू किया जा सकता है (जब टेम्पलेट शाब्दिक के टुकड़ों में शामिल हो) और कस्टम व्यवहार के साथ एक नया टेम्पलेट देता है।

    const createTemplate = fn => function (strings, ...defaults) {
      const [first, ...rest] = strings;
      return (...values) => rest.reduce((acc, curr, i) => {
        return acc + fn(values[i], defaults[i]) + curr;
      }, first);
    };

तब आप उदाहरण के लिए, एम्बेडेड html, css, sql, bash लिखते समय ऐसे मापदंडों को लिख सकते हैं जो स्वचालित रूप से बच जाते हैं या पैरामीटर को साफ कर देते हैं ...

    function sqlSanitize(token, tag) {
      // this is a gross simplification, don't use in production.
      const quoteName = name => (!/^[a-z_][a-z0-9_$]*$/.test(name) ? `"${name.replace(/"/g, '""')}"` : name);
      const quoteValue = value => (typeof value == 'string' ? `'${value.replace(/'/g, "''")}'` : value);
      switch (tag) {
        case 'table':
          return quoteName(token);
        case 'columns':
          return token.map(quoteName);
        case 'row':
          return token.map(quoteValue);
        default:
          return token;
      }
    }

    const sql = createTemplate(sqlSanitize);

इस भोले के साथ (मैं दोहराता हूं, भोले! ) Sql टेम्पलेट हम इस तरह से प्रश्न बना सकते हैं:

    > q  = sql`INSERT INTO ${'table'} (${'columns'})
    ... VALUES (${'row'});`
    > q('user', ['id', 'user name', 'is"Staff"?'], [1, "O'neil", true])
    // `INSERT INTO user (id,"user name","is""Staff""?")
    // VALUES (1,'O''neil',true);`
  1. प्रतिस्थापन के लिए नामांकित मानदंड स्वीकार करें: पहले से दी गई बातों के आधार पर एक कठिन अभ्यास नहीं। इस अन्य उत्तर में एक कार्यान्वयन है ।

  2. रिटर्न ऑब्जेक्ट को एक की तरह व्यवहार करें 'string': ठीक है, यह विवादास्पद है, लेकिन दिलचस्प परिणाम पैदा कर सकता है। इस अन्य उत्तर में दिखाया गया है ।

  3. कॉल साइट पर वैश्विक नाम स्थान के भीतर मापदंडों को हल करें:

मैं तुम्हें देता हूं, पुन: प्रयोज्य टेम्पलेट शाब्दिक:

ठीक है, यह वही है जो ओपी ने दिखाया है उसका आदेश है evil, कमांड का उपयोग करते हुए , मेरा मतलब है eval,। यह बिना किया जा सकता है eval, बस पारित चर नाम को वैश्विक (या विंडो) ऑब्जेक्ट में खोजकर। मैं यह नहीं दिखाऊंगा कि यह कैसे करना है क्योंकि मुझे यह पसंद नहीं है। क्लोजर सही विकल्प हैं।


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


2

सामान्य तौर पर मैं बुराई का उपयोग करने के खिलाफ हूं eval(), लेकिन इस मामले में यह समझ में आता है:

var template = "`${a}.${b}`";
var a = 1, b = 2;
var populated = eval(template);

console.log(populated);         // shows 1.2

यदि आप मान बदलते हैं और कॉल निकालते हैं () फिर से आपको नया परिणाम मिलता है:

a = 3; b = 4;
populated = eval(template);

console.log(populated);         // shows 3.4

यदि आप इसे किसी फ़ंक्शन में चाहते हैं, तो इसे इस तरह लिखा जा सकता है:

function populate(a, b){
  return `${a}.${b}`;
}

यदि आप एक फ़ंक्शन लिख रहे हैं जिसमें टेम्पलेट शामिल है, तो आपको निश्चित रूप से उपयोग नहीं करना चाहिए eval
बरगी

@ बरगी क्यों? यह आपके कार्यान्वयन से कैसे भिन्न है?
जापिर

2
जिन कारणों से मुझे "पता लगता है" किसी भी गतिशील रूप से निर्मित कोड पर लागू होता है। फ़ंक्शन लिखना ताकि यह बिना कॉल किए हुए परिणाम का निर्माण करता eval()है, बिल्कुल वैसा ही है eval(), इसलिए इसमें कोई लाभ नहीं है क्योंकि यह केवल कोड को पढ़ने के लिए कठिन बनाता है।
इपिर

1
बिल्कुल सही। और चूंकि आपका populateफ़ंक्शन कोड को गतिशील रूप से नहीं बनाता है, इसलिए इसे evalअपनी सभी कमियों के साथ उपयोग नहीं करना चाहिए ।
बरगी

6
आपका कार्य केवल function populate(a,b) { return `${a}.${b}`; }
स्पष्ट

1

अद्यतन: निम्नलिखित उत्तर एकल चर नामों तक सीमित है, इसलिए, 'Result ${a+b}'इस तरह के टेम्पलेट इस मामले के लिए मान्य नहीं हैं। हालाँकि आप हमेशा टेम्पलेट मानों के साथ खेल सकते हैं:

format("This is a test: ${a_b}", {a_b: a+b});

मूल ANSWER:

पिछले उत्तरों के आधार पर एक अधिक "मैत्रीपूर्ण" उपयोगिता फ़ंक्शन तैयार करना:

var format = (template, params) => {
    let tpl = template.replace(/\${(?!this\.)/g, "${this.");
    let tpl_func = new Function(`return \`${tpl}\``);

    return tpl_func.call(params);
}

आप इसे वैसे ही चालान कर सकते हैं:

format("This is a test: ${hola}, second param: ${hello}", {hola: 'Hola', hello: 'Hi'});

और परिणामी स्ट्रिंग होनी चाहिए:

'This is a test: Hola, second param: Hi'

इस तरह एक टेम्पलेट के बारे में क्या? `Result: ${a+b}`
एटिरिस

1
हाय @Atiris, आप सही हैं, यह एक सीमा है, मैंने अपना उत्तर अपडेट कर दिया है।
रॉबर्टो

1

यदि आप कुछ नहीं बल्कि सरल (बस निश्चित चर क्षेत्रों, कोई संगणना, सशर्त…) के लिए देख रहे हैं, लेकिन यह भी IE 8,9,10,11 जैसे टेम्पलेट स्ट्रिंग समर्थन के बिना ब्राउज़र पर क्लाइंट-साइड काम करता है …

ये रहा:

fillTemplate = function (templateString, templateVars) {
    var parsed = templateString;
    Object.keys(templateVars).forEach(
        (key) => {
            const value = templateVars[key]
            parsed = parsed.replace('${'+key+'}',value)
        }
    )
    return parsed
}

यह प्रत्येक चर के लिए एक खोज करेगा। एक और तरीका है जो सभी घटनाओं को एक ही बार में बदल देता है जिसे मैंने इस मॉड्यूल में लागू किया है: सुरक्षित-es6-टेम्पलेट
Aalex Gabi

1

मैं लिखने की जरूरत अतिरिक्त अतिरेक पर नाराज था this.हर बार, तो मैं भी तरह चर का विस्तार करने के लिए regex जोड़ा .aकरने के लिए this.a

उपाय:

const interp = template => _thisObj =>
function() {
    return template.replace(/\${([^}]*)}/g, (_, k) =>
        eval(
            k.replace(/([.a-zA-Z0-9$_]*)([a-zA-Z0-9$_]+)/, (r, ...args) =>
                args[0].charAt(0) == '.' ? 'this' + args[0] + args[1] : r
            )
        )
    );
}.call(_thisObj);

इस तरह से उपयोग करें:

console.log(interp('Hello ${.a}${.b}')({ a: 'World', b: '!' }));
// outputs: Hello World!

1

मैं सिर्फ एक एनपीएम पैकेज प्रकाशित करता हूं जो बस यह काम कर सकता है। इस उत्तर से गहराई से प्रेरित ।

const Template = require('dynamic-template-string');

var tpl = new Template('hello ${name}');

tpl.fill({name: 'world'}); // ==> 'hello world';
tpl.fill({name: 'china'}); // ==> 'hello china';

इसका कार्यान्वयन घातक सरल है। काश आपको यह पसंद आए।


module.exports = class Template {
  constructor(str) {
    this._func = new Function(`with(this) { return \`${str}\`; }`);
  }

  fill(data) {
    return this._func.call(data);
  }
}

1

आप इनलाइन एरो फंक्शन का उपयोग इस तरह कर सकते हैं, परिभाषा:

const template = (substitute: string) => `[^.?!]*(?<=[.?\s!])${substitute}(?=[\s.?!])[^.?!]*[.?!]`;

उपयोग:

console.log(template('my replaced string'));

1

रनटाइम टेम्पलेट स्ट्रिंग

var templateString = (template, values) => {
    let output = template;
    Object.keys(values)
        .forEach(key => {
        output = output.replace(new RegExp('\\$' + `{${key}}`, 'g'), values[key]);
    });
    return output;
};

परीक्षा

console.debug(templateString('hello ${word} world', {word: 'wonderful'}));

0

const fillTemplate = (template, values) => {
  template = template.replace(/(?<=\${)\w+(?=})/g, v=>"this."+v);
  return Function.apply(this, ["", "return `"+template+"`;"]).call(values);
};

console.log(fillTemplate("The man ${man} is brother of ${brother}", {man: "John", brother:"Peter"}));
//The man John is brother of Peter

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.