6 ms·
Ah, thanks! Got it. Okay that's wild. I would not expect that to be stable across dynamically-generated template functions, but it seems to work!
by ianthehenry 2y ago
Ah, thanks! Got it. Okay that's wild. I would not expect that to be stable across dynamically-generated template functions, but it seems to work!
- spankalee 2y agoThis is how lit-html implements efficient re-renders of the same template at the same location in DOM. It uses the template strings identity to mark that some DOM was generated from a specific template, and if rendering there again it just skips all the static parts of the template and updates the bound values. Tagged template literals are crazy powerful, and it would be really neat to add some of that magic to other language features. If functions could access the callsite, you could implement React hooks without the whole hooks environment. Each hook could just cache it's state off the callsite object.
- svieira 2y agoThe key thing to note here is that it is completely _lexical_ in scope - this only generates one tagged template even when called multiple times: function lexicalMagic() { const callHistory = []; function tag(strings, ...values) { callHistory.push(strings); // Return a freshly made object return {}; } function evaluateLiteral() { return tag`Hello, ${"world"}!`; } return { evaluateLiteral, callHistory } } We can create multiple "instances" of our closures, just as we expect and they do in fact produce distinct everything-else: > const first = lexicalMagic() > const second = lexicalMagic() > first.evaluateLiteral === second.evaluateLiteral false > first.callHistory === second.callHistory false Using them doesn't behave any differently than the unclosured versions (as expected): > first.evaluateLiteral() === first.evaluateLiteral() false > first.callHistory[0] === first.callHistory[1] true > second.evaluateLiteral() === second.evaluateLiteral() false > second.callHistory[0] === second.callHistory[1] true However, there is only one instance of the template literal, not two as we might expect. This is really helpful for some cases, but it definitely is surprising given the rest-of-JS: > first.callHistory[0] === second.callHistory[1] true