标签模板
- “标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
- 如果模板字符里面有变量,会将模板字符串先处理成多个参数,再调用函数。
- 函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分。
假设有以下函数:
let a = 1;
let b = 2;
function tag(x,y){
return x,y;
}
tag`this is ${a} and ${a+b}`;
注意,由于使用模板字符串形式,第一个参数会是一个只接收非变量的数组(存在一个raw属性,用来保存转以后的原字符串),所以这里会输出,可以看到输出参数并不全,因为非变量数组占用了一个变量位置:
["this is" , " and " , "" ] 1
//x即为存放非变量的数组,故y为第二个参数1
相当于这么调用的函数:
tag(["this is","and",""],1,3);
所以如果想取到全部的参数可以:
//1,对应相同数量的参数
function tag(x,y,z){
return x,y,z // y = 1 , z = 3
}
//2,使用reset参数
function tag(x , ...y){
return x,y; //x = ['this is' , 'and' , ""] y = [1,3]
}
//3,arugments
function tag(x){
return arguments; //0:['this is' , 'and' , ''] 1:1 2:3
}
按照调用的语句拼接:
function tag(x,...y){
let output = '';
y.forEach((item,index)=>{
output += x[index] + item;
})
output += x[y.length];
return output; // this is 1 and 3
}
常见用法:防止用户恶意插入代码进行XSS攻击,场景:(借鉴自https://blog.csdn.net/qq_43287488/article/details/82873336)
1、攻击者通过评论表单提交将<script>alert(‘aaa’)</script>
提交到网站
2、网站后端对提交的评论数据不做任何操作,直接存储到数据库中
3、其他用户访问正常访问网站,并且需要请求网站的评论数据
4、网站后端会从数据库中取出数据,直接返回给用户
5、用户得到页面后,直接运行攻击者提交的代码<script>alert(‘aaa’)</script>
,所有用户都会在网页中弹出aaa的弹窗
应用:
function safeHTML(templateData,...reset){
let s = templateData[0];
reset.foreach((item,index)=>{
let arg = String(item);
s += arg.replace(/&/g,"&") //将&转换为字符串&amg
.replace(/</g,"<") //将<转换为字符串<
.replace(/>/g,">"); //将>转换为>
s += templateData[index];
})
return s; //返回转义后的字符串
}
let sender = '<script>alert("abc") < /script>'; // 用户输入的恶意代码
let message = SaferHTML`<p>${sender} has sent you a message.</p>`;
// message -> <p><script>alert("abc") < /script><p>
标签函数与模板编译结合,参照官网例子:
// 下面的hashTemplate函数
// 是一个自定义的模板处理函数
let libraryHtml = hashTemplate`
<ul>
#for book in ${myBooks}
<li><i>#{book.title}</i> by #{book.author}</li>
#end
</ul>
`;
按照自己想法处理了一下,主要原理参照模板编译,正则替换为JavaScript表达式进行解析:
let myBooks = [{
title: "ES6",
author: "Javascript"
}];
let libraryHtml = hashTemplate `
<ul>
#for book of ${myBooks}
<li><i>#{book.title}</i> by #{book.author}</li>
#end
</ul>
`;
function hashTemplate(template, ...reset) {
let output = '';
//正则表达式转换
let delbrackets = /<(.+?)>/g , //()中的内容
delbraces = /#{(.+?)}/g , //{}中的内容
changefor = /#for/g, //#for的更改
changeend = /#end/g; //#end的替换
template.forEach((element, index) => {
//用三元判断拼接的顺序
index > 0 ? output += element : output += element + 'myBooks){';
});
//使用replace进行替换,by字符串实属无奈,学艺不精
output = output
.replace(delbrackets, 'echo(`<$1>`) \n')
.replace(delbraces, '\n echo($1)\n')
.replace(changefor, 'for(')
.replace(changeend, '}')
.replace(/(by)/g, ' echo(`$1`) ');
let script =
`
(function parse(myBooks){
let html = '';
function echo(str){
html+=str;
}
${output}
return html;
})
`
let parse = eval(script);
document.querySelector('div').innerHTML = parse(...reset);
}
该方法类似于模板编译实例的解法,更改完输出的字符串为:
(function parse(myBooks) {
let html = '';
function echo(str) {
html += str;
}
echo(`<ul>`)
for (book of myBooks) {
echo(`<li>`)
echo(`<i>`)
echo(book.title)
echo(`</i>`)
echo(`by`)
echo(book.author)
echo(`</li>`)
}
echo(`</ul>`)
return html;
})
String.raw()
用来充当模板字符串的处理函数,返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串。
String.raw`Hi\n${2+3}!`;
// 返回 "Hi\\n5!"
String.raw`Hi\u000A!`;
// 返回 "Hi\\u000A!"
正则的扩展(暂时跳过)
数值的扩展
新增方法:
- Number.isFinite() 用来检查一个数值是否为有限的(finite)
- Number.isNaN()用来检查一个值是否为NaN。
-
而这两个新方法只对数值有效,Number.isFinite()对于非数值一律返回false, Number.isNaN()只有对于NaN才返回true,非NaN一律返回false。
-
ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,Number.parseInft(),Number.parseFloat()。
-
Number.isInteger()用来判断一个数值是否为整数,如果数值的精度超过这个限度,第54位及后面的位就会被丢弃,这种情况下,Number.isInteger可能会误判。
-
如果对数据精度的要求较高,不建议使用Number.isInteger()判断一个数值是否为整数。
-
Number.EPSILON,JavaScript 能够表示的最小精度,实质是一个可以接受的最小误差范围。
-
Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。
-
Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内。
Math对象的拓展
ES6 在 Math 对象上新增了 17 个与数学相关的方法。所有这些方法都是静态方法,只能在 Math 对象上调用。
-
Math.trunc方法用于去除一个数的小数部分,返回整数部分,对于非数值,Math.trunc内部使用Number方法将其先转为数值,对于空值和无法截取整数的值,返回NaN。
-
Math.sign方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值,如果参数是非数值,会自动转为数值。对于那些无法转为数值的值,会返回NaN。
-
返回五种值:
参数为正数,返回+1; 参数为负数,返回-1; 参数为 0,返回0; 参数为-0,返回-0; 其他值,返回NaN。
-
Math.cbrt()方法用于计算一个数的立方根,对于非数值,先使用Number方法将其转为数值。
-
Math.clz32()方法将参数转为 32 位无符号整数的形式,然后这个 32 位值里面有多少个前导 0,对于空值或其他类型的值,Math.clz32方法会将它们先转为数值,然后再计算。
-
Math.imul()方法返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。
-
Math.fround()方法返回一个数的32位单精度浮点数形式,主要作用,是将64位双精度浮点数转为32位单精度浮点数,对于 NaN 和 Infinity,此方法返回原值。对于其它类型的非数值,Math.fround 方法会先将其转为数值,再返回单精度浮点数。
-
Math.hypot()方法返回所有参数的平方和的平方根,如果参数不是数值,Math.hypot方法会将其转为数值。只要有一个参数无法转为数值,就会返回 NaN。
对数方法
Math.expm1(x)
返回 ex - 1,即Math.exp(x) - 1
。Math.log1p(x)
方法返回1 + x
的自然对数,即Math.log(1 + x)
。如果x
小于-1,返回NaN
。Math.log10(x)
返回以 10 为底的x
的对数。如果x
小于 0,则返回 NaN。Math.log2(x)
返回以 2 为底的x
的对数。如果x
小于 0,则返回 NaN。
双曲函数方法
ES6 新增了 6 个双曲函数方法。
Math.sinh(x)
返回x
的双曲正弦(hyperbolic sine)Math.cosh(x)
返回x
的双曲余弦(hyperbolic cosine)Math.tanh(x)
返回x
的双曲正切(hyperbolic tangent)Math.asinh(x)
返回x
的反双曲正弦(inverse hyperbolic sine)Math.acosh(x)
返回x
的反双曲余弦(inverse hyperbolic cosine)Math.atanh(x)
返回x
的反双曲正切(inverse hyperbolic tangent)
ES2016 新增了一个指数运算符(**
),特点是右结合,而不是常见的左结合。多个指数运算符连用时,是从最右边开始计算的。
2 ** 2 // 4
2 ** 3 // 8
// 相当于 2 ** (3 ** 2)
2 ** 3 ** 2
// 512
指数运算符可以与等号结合,形成一个新的赋值运算符(**=
)。
let a = 1.5;
a **= 2;
// 等同于 a = a * a;
let b = 4;
b **= 3;
// 等同于 b = b * b * b;