前言
Hello, 各位前端探险家们!这里是前端的日常,今天我想和大家聊聊关于 ES6 模板字符串的那些事儿。
大家都知道,模板字符串是一个很好用的工具,可以用来拼接字符串。但其实,它的能力远不止于此。接下来,我带大家一起挖掘它的隐藏超能力!
模板字符串:不只是"字符串拼接"
模板字符串,正式的叫法应该是"模板字面量"。官方文档的定义是:模板字面量是用反引号( ````` )分隔的字面量,允许多行字符串、带嵌入表达式的字符串插值以及一种叫带标签的模板的特殊结构。模板字面量有时被非正式地称为"模板字符串",因为它最常被用于字符串插值。
在日常开发中,我们经常用它来拼接字符串,比如打印日志或者生成简单的动态文本。例如:
ini
const name = 'Alice';
const str = `Hello, ${name}!`;
console.log(str); // Hello, Alice!
这确实很方便,但它的强大之处远不止于此。
一、带标签的模板字面量
带标签的模板字面量可能不会生成字符串。它可以与自定义的标签函数一起使用,对模板字面量的不同部分执行任何操作。这里的"标签"是一个函数,模板字符串会在运行时将字符串拆分后的各个部分传递给这个函数。
举个例子,先来看一个简单的错误示范:
ini
const name = 'Bob';
const age = 25;
const bio = myTag`Name: ${name} - Age: ${age}`;
console.log(bio); // 报错:myTag is not defined
啊,报错了!因为 myTag
没有被定义。接下来,让我们定义这个函数。
javascript
function myTag(strings, ...values) {
console.log(strings); // ['Name: ', ' - Age: ', '']
console.log(values); // ['Bob', 25]
// 我们可以在这里对这些数据做任何操作
return values.map(value => `(${value})`).join(''); // 这里只是个简单示例
}
const name = 'Charlie';
const age = 30;
const bio = myTag`Name: ${name} - Age: ${age}`;
console.log(bio); // (Charlie)(30)
看到没有,myTag
函数接收两个参数:strings
和 values
。
- •
strings
是一个数组,包含模板字符串中的非插值部分。 - •
values
是插值表达式的值组成的数组。
也就是说,strings
的长度比 values
的长度多 1。比如上面的例子中,strings
有 3 个元素,values
有 2 个元素。
二、带标签的模板字面量的高级玩法
带标签的模板字面量结合一些脑洞大开的想法,可以实现很多有趣的功能。
1. 自定义格式化输出
我们可以用它来实现自动格式化的功能,比如将所有的插值内容转换成大写字母:
javascript
function upperCase(strings, ...values) {
return strings.reduce((acc, s, i) => {
const value = values[i] ? values[i].toUpperCase() : '';
return acc + s + value;
}, '');
}
const message = upperCase`hello ${'world'}, welcome ${'to'} my blog.`;
console.log(message); // Hello WORLD, Welcome TO my blog.
这种功能在需要统一格式化的地方非常有用,比如生成特定风格的文档。
2. 生成安全的 HTML
如果我们需要在页面中插入 HTML 内容,用模板字符串结合标签函数可以防止 XSS 攻击。比如:
javascript
function safeHtml(strings, ...values) {
return strings.reduce((acc, s, i) => {
let value = values[i] || '';
value = value.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
return acc + s + value;
}, '');
}
const html = safeHtml`<div>${'This is a <script>malicious code</script>'}</div>`;
console.log(html); // <div>This is a <script>malicious code</script></div>
这可以有效避免恶意代码注入页面。
3. 国际化支持
如果我们要实现简单的国际化功能,带标签的模板字面量也能派上用场。比如:
javascript
const i18n = (strings, ...values) => {
const lang = navigator.language || 'en-US';
const translations = {
'en-US': { greeting: 'Hello', name: 'Name' },
'zh-CN': { greeting: '你好', name: '名字' },
};
return strings.map((s, i) => {
const key = s.trim();
const trans = translations[lang][key] || s;
const value = values[i] ? ` (${values[i]})` : '';
return `${trans}${value}`;
}).join('');
};
const greeting = i18n`greeting ${'Alice'}, your name is ${'Alice'}!`;
console.log(greeting); // 根据语言环境输出不同内容
4. CSS-in-JS
在 React 中,styled-components
是一个非常流行的 CSS-in-JS 库。它内部就是用带标签的模板字面量来实现的。比如:
css
const Title = styled.h1`
font-size: 2em;
color: #61dafb;
`;
const Wrapper = styled.div`
padding: 1em;
background: #f0f0f0;
`;
三、如何实现一个简易版的 styled-components
其实,styled-components
的原理并不复杂。我们可以用标签函数来动态生成组件的样式。比如:
javascript
function styled(tagName) {
return function (strings, ...values) {
return class extends React.Component {
render() {
const style = strings.reduce((acc, s, i) => {
const val = values[i];
if (!val) return acc + s;
if (typeof val === 'function') {
return acc + s + val();
}
return acc + s + val;
}, '');
return React.createElement(tagName, { style }, this.props.children);
}
};
};
}
// 使用方法
const Button = styled('button')`
background: ${props => props.primary ? 'blue' : 'gray'};
color: white;
padding: 10px;
border-radius: 5px;
`;
// 渲染
<Button primary>Click me</Button>
结语
模板字符串的魅力远不止简单的字符串拼接,它结合标签函数之后,就像是一把瑞士军刀,可以应对各种复杂的场景。希望你能在实际开发中用上这些技巧,让你的代码更加优雅和强大。
如果喜欢这篇内容,别忘了点亮"在看",分享给更多的开发者朋友哦!