本篇内容主要讲解“es6语法糖怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“es6语法糖怎么使用”吧! es6语法糖有:1、对象字面量,是指以“{}”形式直接表示的对象;2、箭头函数,一种写匿名函数的新方法;3、解构赋值,允许按照一定的模式,从数组或对象中提取值,给变量进行赋值;4、剩余参数和拓展符;5、模板字符串;6、let和const声明语句。语法糖:是指编程语言中可以更容易的表达一个操作的语法,它可以使程序员更加容易去使用这门语言,操作可以变得更加清晰、方便,或者更加符合程序员的编程习惯。ES6为一些已有的功能提供了非破坏性更新,这类更新中的大部分我们可以理解为语法糖,称之为语法糖,意味着,这类新语法能做的事情其实用ES5也可以做,只是会稍微复杂一些。本章我们将着重讨论这些语法糖,看完之后,可能你会对一些你很熟悉的ES6新语法有不一样的理解。对象字面量是指以{}
形式直接表示的对象,比如下面这样:
varbook={ title:'ModularES6', author:'Nicolas', publisher:'OReilly' }
ES6 为对象字面量的语法带来了一些改进:包括属性/方法的简洁表示,可计算的属性名等等,我们逐一来看:你有没有遇到过这种场景,一个我们声明的对象中包含若干属性,其属性值由变量表示,且变量名和属性名一样的。比如下面这样,我们想把一个名为 listeners
的数组赋值给events
对象中的listeners
属性,用ES5我们会这样做:
varlisteners=[] functionlisten(){} varevents={ listeners:listeners, listen:listen }
ES6则允许我们简写成下面这种形式:
varlisteners=[] functionlisten(){} varevents={listeners,listen}
怎么样,是不是感觉简洁了许多,使用对象字面量的简洁写法让我们在不影响语义的情况下减少了重复代码。这是ES6带来的好处之一,它提供了众多更简洁,语义更清晰的语法,让我们的代码的可读性,可维护性大大提升。对象字面量的另一个重要更新是允许你使用可计算的属性名,在ES5中我们也可以给对象添加属性名为变量的属性,一般说来,我们要按下面方法这样做,首先声明一个名为expertise
的变量,然后通过person[expertise]
这种形式把变量添加为对象person
的属性:
varexpertise='journalism' varperson={ name:'Sharon', age:27 } person[expertise]={ years:5, interests:['international','politics','internet'] }
ES6 中,对象字面量可以使用计算属性名了,把任何表达式放在中括号中,表达式的运算结果将会是对应的属性名,上面的代码,用ES6可以这样写:
varexpertise='journalism' varperson={ name:'Sharon', age:27, [expertise]:{ years:5, interests:['international','politics','internet'] } }
不过需要注意的是,简写属性和计算的属性名不可同时使用。这是因为,简写属性是一种在编译阶段的就会生效的语法糖,而计算的属性名则在运行时才生效。如果你把二者混用,代码会报错。而且二者混用往往还会降低代码的可读性,所以JavaScript在语言层面上限制二者不能混用也是个好事。
varexpertise='journalism' varjournalism={ years:5, interests:['international','politics','internet'] } varperson={ name:'Sharon', age:27, [expertise]//这里会报语法错误 }
遇到以下情景时,可计算的属性名会让我们的代码更简洁:某个新对象的属性引自另一个对象:
vargrocery={ id:'bananas', name:'Bananas', units:6, price:10, currency:'USD' } vargroceries={ [grocery.id]:grocery }
需构建的对象的属性名来自函数参数。如果使用ES5来处理这种问题,我们需要先声明一个对象字面量,再动态的添加属性,再返回这个对象。下面的例子中,我们创建了一个响应Ajax请求的函数,这个函数的作用在于,请求失败时,返回的对象拥有一个名为error
属性及对应的描述,请求成功时,该对象拥有一个名为success
属性及对应的描述。
//ES5写法 functiongetEnvelope(type,description){ varenvelope={ data:{} } envelope[type]=description returnenvelope }
使用ES6提供的利用计算属性名,更简洁的实现如下:
//ES6写法 functiongetEnvelope(type,description){ return{ data:{}, [type]:description } }
对象字面量的属性可以简写,方法其实也是可以的。我们先看看传统上如何定义对象方法,下述代码中,我们构建了一个事件发生器,其中的on
方法用以注册事件,emit
方法用以执行事件:
varemitter={ events:{}, on:function(type,fn){ if(this.events[type]===undefined){ this.events[type]=[] } this.events[type].push(fn) }, emit:function(type,event){ if(this.events[type]===undefined){ return } this.events[type].forEach(function(fn){ fn(event) }) } }
ES6 的对象字面量方法简写允许我们省略对象方法的function
关键字及之后的冒号,改写后的代码如下:
varemitter={ events:{}, on(type,fn){ if(this.events[type]===undefined){ this.events[type]=[] } this.events[type].push(fn) }, emit(type,event){ if(this.events[type]===undefined){ return } this.events[type].forEach(function(fn){ fn(event) }) } }
ES6中的箭头函数可谓大名鼎鼎了,它有一些特别的优点(关于this
),可能你和我一样,使用箭头函数很久了,不过有些细节我之前却一直不了解,比如箭头函数的几种简写形式及使用注意事项。JS中声明的普通函数,一般有函数名,一系列参数和函数体,如下:
functionname(parameters){ //functionbody }
普通匿名函数则没有函数名,匿名函数通常会被赋值给一个变量/属性,有时候还会被直接调用:
varexample=function(parameters){ //functionbody }
ES6 为我们提供了一种写匿名函数的新方法,即箭头函数。箭头函数不需要使用function
关键字,其参数和函数体之间以=>
相连接:
varexample=(parameters)=>{ //functionbody }
尽管箭头函数看起来类似于传统的匿名函数,他们却具有根本性的不同:箭头函数不能被直接命名,不过允许它们赋值给一个变量;箭头函数不能用做构造函数,你不能对箭头函数使用new
关键字;箭头函数也没有prototype
属性;箭头函数绑定了词法作用域,不会修改this
的指向。最后一点是箭头函数最大的特点,我们来仔细看看。我们在箭头函数的函数体内使用的this
,arguments
,super
等都指向包含箭头函数的上下文,箭头函数本身不产生新的上下文。下述代码中,我们创建了一个名为timer
的对象,它的属性seconds
用以计时,方法start
用以开始计时,若我们在若干秒后调用start
方法,将打印出当前的seconds
值。
//ES5 vartimer={ seconds:0, start(){ setInterval(function(){ this.seconds++ },1000) } } timer.start() setTimeout(function(){ console.log(timer.seconds) },3500) >0
//ES6 vartimer={ seconds:0, start(){ setInterval(()=>{ this.seconds++ },1000) } } timer.start() setTimeout(function(){ console.log(timer.seconds) },3500) //
第一段代码中start
方法使用的是常规的匿名函数定义,在调用时this
将指向了window
,console
出的结果为undefined
,想要让代码正常工作,我们需要在start
方法开头处插入var self = this
,然后替换匿名函数函数体中的this
为self
,第二段代码中,我们使用了箭头函数,就不会发生这种情况了。还需要说明的是,箭头函数的作用域也不能通过.call
,.apply
,.bind
等语法来改变,这使得箭头函数的上下文将永久不变。我们再来看另外一个箭头函数与普通匿名函数的不同之处,你猜猜,下面的代码最终打印出的结果会是什么:
functionpuzzle(){ returnfunction(){ console.log(arguments) } } puzzle('a','b','c')(1,2,3)
答案是1,2,3
,原因是对常规匿名函数而言,arguments
指向匿名函数本身。作为对比,我们看看下面这个例子,再猜猜,打印结果会是什么?
functionpuzzle(){ return()=>{ console.log(arguments) } } puzzle('a','b','c')(1,2,3)
答案是a,b,c
,箭头函数的特殊性决定其本身没有arguments
对象,这里的arguments
其实是其父函数puzzle
的。前面我们提到过,箭头函数还可以简写,接下来我们一起看看。完整的箭头函数是这样的:
varexample=(parameters)=>{ //functionbody }
简写1:当只有一个参数时,我们可以省略箭头函数参数两侧的括号:
vardouble=value=>{ returnvalue*2 }
简写2:对只有单行表达式且,该表达式的值为返回值的箭头函数来说,表征函数体的{}
,可以省略,return
关键字可以省略,会静默返回该单一表达式的值。
vardouble=(value)=>value*2
简写3:上述两种形式可以合并使用,而得到更加简洁的形式
vardouble=value=>value*2
现在,你肯定学会了箭头函数的基本使用方法,接下来我们再看几个使用示例。当你的简写箭头函数返回值为一个对象时,你需要用小括号括起你想返回的对象。否则,浏览器会把对象的{}
解析为箭头函数函数体的开始和结束标记。
//正确的使用形式 varobjectFactory=()=>({modular:'es6'})
下面的代码会报错,箭头函数会把本想返回的对象的花括号解析为函数体,number
被解析为label
,value
解释为没有做任何事情表达式,我们又没有显式使用return
,返回值默认是undefined
。
[1,2,3].map(value=>{number:value}) //
当我们返回的对象字面量不止一个属性时,浏览器编译器不能正确解析第二个属性,这时会抛出语法错误。
[1,2,3].map(value=>{number:value,verified:true}) //
解决方案是把返回的对象字面量包裹在小括号中,以助于浏览器正确解析:
[1,2,3].map(value=>({number:value,verified:true})) /*
其实我们并不应该盲目的在一切地方使用ES6,ES6也不是一定比ES5要好,是否使用主要看其能否改善代码的可读性和可维护性。箭头函数也并非适用于所有的情况,比如说,对于一个行数很多的复杂函数,使用=>
代替function
关键字带来的简洁性并不明显。不过不得不说,对于简单函数,箭头函数确实能让我们的代码更简洁。给函数以合理的命名,有助于增强程序的可读性。箭头函数并不能直接命名,但是却可以通过赋值给变量的形式实现间接命名,如下代码中,我们把箭头函数赋值给变量 throwError
,当函数被调用时,会抛出错误,我们可以追溯到是箭头函数throwError
报的错。
varthrowError=message=>{ thrownewError(message) } throwError('thisisawarning')
如果你想完全控制你的函数中的this
,使用箭头函数是简洁高效的,采用函数式编程尤其如此。
[1,2,3,4] .map(value=>value*2) .filter(value=>value>2) .forEach(value=>console.log(value))//
ES6提供的最灵活和富于表现性的新特性莫过于解构了。一旦你熟悉了,它用起来也很简单,某种程度上解构可以看做是变量赋值的语法糖,可应用于对象,数组甚至函数的参数。为了更好的描述对象解构如何使用,我们先构建下面这样一个对象(漫威迷一定知道这个对象描述的是谁):
//描述BruceWayne的对象 varcharacter={ name:'Bruce', pseudonym:'Batman', metadata:{ age:34, gender:'male' }, batarang:['gaspellet','bat-mobilecontrol','bat-cuffs'] }
假如现有有一个名为 pseudonym
的变量,我们想让其变量值指向character.pseudonym
,使用ES5,你往往会按下面这样做:
varpseudonym=character.pseudonym
ES6致力于让我们的代码更简洁,通过ES6我们可以用下面的代码实现一样的功能:
var{pseudonym}=character
如同你可以使用var
加逗号在一行中同时声明多个变量,解构的花括号内使用逗号可以做一样的事情。
var{pseudonym,name}=character
我们还可以混用解构和常规的自定义变量,这也是解构语法灵活性的表现之一。
var{pseudonym}=character,two=2
解构还允许我们使用别名,比如我们想把character.pseudonym
赋值给变量 alias
,可以按下面的语句这样做,只需要在pseudonym
后面加上:
即可:
var{pseudonym:alias}=character console.log(alias) //
解构还有另外一个强大的功能,解构值还可以是对象:
var{metadata:{gender}}=character
当然,对于多层解构,我们同样可以赋予别名,这样我们可以通过非常简洁的方法修改子属性的名称:
var{metadata:{gender:characterGender}}=character
在ES5 中,当你调用一个未曾声明的值时,你会得到undefined
:
console.log(character.boots) //
使用解构,情况也是类似的,如果你在左边声明了一个右边对象中不存在的属性,你也会得到undefined
.
var{boots}=character console.log(boots) //
对于多层解构,如下述代码中,boots
并不存在于character
中,这时程序会抛出异常,这就好比你你调用undefined
或者null
的属性时会出现异常。
var{boots:{size}}=character //
解构其实就是一种语法糖,看以下代码,你肯定就能很快理解为什么会抛出异常了。
varnothing=null varmissing=nothing.missing //
解构也可以添加默认值,如果右侧不存在对应的值,默认值就会生效,添加的默认值可以是数值,字符串,函数,对象,也可以是某一个已经存在的变量:
var{boots={size:10}}=character console.log(boots) //
对于多层的解构,同样可以使用默认值
var{metadata:{enemy='Satan'}}=character console.log(enemy) //
默认值和别名也可以一起使用,不过需要注意的是别名要放在前面,默认值添加给别名:
var{boots:footwear={size:10}}=character
对象解构同样支持计算属性名,但是这时候你必须要添加别名,这是因为计算属性名允许任何类似的表达式,不添加别名,浏览器解析时会有问题,使用如下:
var{['boo'+'ts']:characterBoots}=character console.log(characterBoots) //
还是那句话,我们也不是任何情况下都应该使用解构,语句characterBoots = character[type]
看起来比{ [type]: characterBoots } = character
语义更清晰,但是当你需要提取对象中的子对象时,解构就很简洁方便了。我们再看看在数组中该如何使用解构。数组解构的语法和对象解构是类似的。区别在于,数组解构我们使用中括号而非花括号,下面的代码中,通过结构,我们在数组coordinates
中提出了变量 x,y
。 你不需要使用x = coordinates[0]
这样的语法了,数组解构不使用索引值,但却让你的代码更加清晰。
varcoordinates=[12,-7] var[x,y]=coordinates console.log(x) //
数组解构也允许你跳过你不想用到的值,在对应地方留白即可:
varnames=['James','L.','Howlett'] var[firstName,,lastName]=names console.log(lastName) //
和对象解构一样,数组解构也允许你添加默认值:
varnames=['James','L.'] var[firstName='John',,lastName='Doe']=names console.log(lastName) //
在ES5中,你需要借助第三个变量,才能完成两个变量值的交换,如下:
varleft=5,right=7; varaux=left left=right right=aux
使用解构,一切就简单多了:
varleft=5,right=7; [left,right]=[right,left]
我们再看看函数解构。在ES6中,我们可以给函数的参数添加默认值了,下例中我们就给参数 exponent
分配了一个默认值:
functionpowerOf(base,exponent=2){ returnMath.pow(base,exponent) }
箭头函数同样支持使用默认值,需要注意的是,就算只有一个参数,如果要给参数添加默认值,参数部分一定要用小括号括起来。
vardouble=(input=0)=>input*2
我们可以给任何位置的任何参数添加默认值。
functionsumOf(a=1,b=2,c=3){ returna+b+c } console.log(sumOf(undefined,undefined,4)) //
在JS中,给一个函数提供一个包含若干属性的对象字面量做为参数的情况并不常见,不过你依旧可以按下面方法这样做:
vardefaultOptions={brand:'Volkswagen',make:1999} functioncarFactory(options=defaultOptions){ console.log(options.brand) console.log(options.make) } carFactory() //
不过这样做存在一定的问题,当你调用该函数时,如果传入的参数对象只包含一个属性,另一个属性的默认值会自动失效:
carFactory({make:2000}) //
函数参数解构就可以解决这个问题。通过函数参数解构,可以解决上面的问题,这里我们为每一个属性都提供了默认值,单独改变其中一个并不会影响其它的值:
functioncarFactory({brand='Volkswagen',make=1999}){ console.log(brand) console.log(make) } carFactory({make:2000}) //
不过这种情况下,函数调用时,如果参数为空即carFactory()
函数将抛出异常。这种问题可以通过下面的方法来修复,下述代码中我们添加了一个空对象作为options
的默认值,这样当函数被调用时,如果参数为空,会自动以{}
作为参数。
functioncarFactory({ brand='Volkswagen', make=1999 }={}){ console.log(brand) console.log(make) } carFactory() //
除此之外,使用函数参数解构,还可以让你的函数自行匹配对应的参数,看接下来的例子,你就能明白这一点了,我们定义一个名为car
的对象,这个对象拥有很多属性:owner,brand,make,model,preferences等等。
varcar={ owner:{ id:'e2c3503a4181968c', name:'DonaldDraper' }, brand:'Peugeot', make:2015, model:'208', preferences:{ airbags:true, airconditioning:false, color:'red' } }
解构能让我们的函数方便的只使用里面的部分数据,下面代码中的函数getCarProductModel
说明了具体该如何使用:
vargetCarProductModel=({brand,make,model})=>({ sku:brand+':'+make+':'+model, brand, make, model }) getCarProductModel(car)
当一个函数的返回值为对象或者数组时,使用解构,我们可以非常简洁的获取返回对象中某个属性的值(返回数组中某一项的值)。比如说,函数getCoordinates()
返回了一系列的值,但是我们只想用其中的x,y
,我们可以这样写,解构帮助我们避免了很多中间变量的使用,也使得我们代码的可读性更高。
functiongetCoordinates(){ return{x:10,y:22,z:-1,type:'3d'} } var{x,y}=getCoordinates()
通过使用默认值,可以减少重复,比如你想写一个random
函数,这个函数将返回一个位于min
和max
之间的值。我们可以分辨设置min
默认值为1,max
默认值为10,在需要的时候还可以单独改变其中的某一个值:
functionrandom({min=1,max=10}={}){ returnMath.floor(Math.random()*(max-min))+min } console.log(random())//
解构还可以配合正则表达式使用。看下面这个例子:
functionsplitDate(date){ varrdate=/(d+).(d+).(d+)/ returnrdate.exec(date) } var[,year,month,day]=splitDate('2015-11-06')
不过当.exec
不比配时会返回null
,因此我们需要修改上述代码如下:
varmatches=splitDate('2015-11-06')if(matches===null){ return } var[,year,month,day]=matches
下面我们继续来讲讲spread
和rest
操作符。ES6之前,对于不确定数量参数的函数。你需要使用伪数组arguments
,它拥有length
属性,却又不具备很多一般数组有的特性。需要通过Array#slice.call
转换arguments
对象真数组后才能进行下一步的操作:
functionjoin(){ varlist=Array.prototype.slice.call(arguments) returnlist.join(',') } join('first','second','third')//
对于这种情况,ES6提供了一种更好的解决方案:rest
。使用rest
, 你只需要在任意JavaScript函数的最后一个参数前添加三个点...
即可。当rest
参数是函数的唯一参数时,它就代表了传递给这个函数的所有参数。它起到和前面说的.slice
一样的作用,把参数转换为了数组,不需要你再对arguments
进行额外的转换了。
functionjoin(...list){ returnlist.join(',') } join('first','second','third')//
rest
参数之前的命名参数不会被包含在rest
中,
functionjoin(separator,...list){ returnlist.join(separator) } join(';','first','second','third')//
在箭头函数中使用rest
参数时,即使只有这一个参数,也需要使用圆括号把它围起来,不然就会报错SyntaxError
,使用示例如下:
varsumAll=(...numbers)=>numbers.reduce( (total,next)=>total+next ) console.log(sumAll(1,2,5))//
上述代码的ES5实现如下:
//ES5的写法 functionsumAll(){ varnumbers=Array.prototype.slice.call(arguments) returnnumbers.reduce(function(total,next){ returntotal+next }) } console.log(sumAll(1,2,5))//
拓展运算符可以把任意可枚举对象转换为数组,使用拓展运算符可以高效处理目标对象,在拓展目前前添加...
就可以使用拓展运算符了。下例中...arguments
就把函数的参数转换为了数组字面量。
functioncast(){ return[...arguments] } cast('a','b','c')//
使用拓展运算符,我们也可以把字符串转换为由每一个字母组成的数组:
[...'showme']//
使用拓展运算符,还可以拼合数组:
functioncast(){ return['left',...arguments,'right'] } cast('a','b','c')//
varall=[1,...[2,3],4,...[5],6,7] console.log(all)//
这里我还想再强调一下,拓展运算符不仅仅适用于数组和arguments
对象,对任意可迭代的对象都可以使用。迭代也是ES6新提出的一个概念,在[ Iteration and Flow Control]()这一章,我们将详细叙述迭代。当你想要抽出一个数组的前一个或者两个元素时,常用的解决方案是使用.shift
.尽管是函数式的,下述代码在第一次看到的时候却不好理解,我们使用了两次.slice
从list
中抽离出两个不同的元素。
varlist=['a','b','c','d','e'] varfirst=list.shift() varsecond=list.shift() console.log(first)//
在ES6中,结合使用拓展和解构,可以让代码的可读性更好:
var[first,second,...other]=['a','b','c','d','e'] console.log(other)//
除了对数组进行拓展,你同样可以对函数参数使用拓展,下例展示了如何添加任意数量的参数到multiply
函数中。
functionmultiply(left,right){ returnleft*right } varresult=multiply(...[2,3]) console.log(result)//
向在数组中一样,函数参数中的拓展运算符同样可以结合常规参数一起使用。下例中,print
函数结合使用了rest
,普通参数,和拓展运算符:
functionprint(...list){ console.log(list) } print(1,...[2,3],4,...[5])//
下表总结了,拓展运算符的常见使用方法:模板字符串是对常规JavaScript
字符串的重大改进,不同于在普通字符串中使用单引号或者双引号,模板字符串的声明需要使用反撇号,如下所示:
vartext=`Thisismyfirsttemplateliteral`
因为使用的是反撇号,你可以在模板字符串中随意使用单双引号了,使用时不再需要考虑转义,如下:
vartext=`I'm"amazed"attheseopportunities!`
模板字符串具有很多强大的功能,可在其中插入JavaScript表达式就是其一。通过模板字符串,你可以在模板中插入任何JavaScript表达式了。当解析到表达式时,表达式会被执行,该处将渲染表达式的值,下例中,我们在字符串中插入了变量name
:
varname='Shannon' vartext=`Hello,${name}!` console.log(text)//
模板字符串是支持任何表达式的。使用模板字符串,代码将更容易维护,你无须再手动连接字符串和JavaScript表达式了。看下面插入日期的例子,是不是又直观又方便:
`Thetimeanddateis${newDate().toLocaleString()}.`//
表达式中还可以包含数学运算符:
`Theresultof2+3equals${2+3}`//
鉴于模板字符串本身也是JavaScript表达式,我们在模板字符串中还可以嵌套模板字符串;
`Thistemplateliteral${`is${'nested'}`}!`//
模板字符串的另外一个优点是支持多行字符串;在ES6之前,如果你想表现免费云主机、域名多行字符串,你需要使用转义,数组拼合,甚至使用使用注释符做复杂的hacks.如下所示:
varescaped='Thefirstlinen Asecondlinen Thenathirdline' varconcatenated='Thefirstlinen'` 'Asecondlinen'`'Thenathirdline' varjoined=['Thefirstline','Asecondline','Thenathirdline'].join('n')
应用ES6,这种处理就简单多了,模板字符串默认支持多行:
varmultiline=`Thefirstline Asecondline Thenathirdline`
当你需要返回的字符串基于html
和数据生成,使用模板字符串是很简洁高效的,如下所示:
varbook={ title:'ModularES6', excerpt:'HeregoessomeproperlysanitizedHTML', tags:['es6','template-literals','es6-in-depth'] } varhtml=`${book.title}
${book.excerpt} `
上述代码将得到下面这样的结果。空格得以保留,多个li
也按我们的预期被合适的渲染:
ModularES6
HeregoessomeproperlysanitizedHTML
不过有时候我们并不希望空格被保留,下例中我们在函数中使用包含缩进的模板字符串,我们希望结果没有缩进,但是实际的结果却有四格的缩进。
functiongetParagraph(){ return` DearRod, Thisisatemplateliteralstringthat'sindented fourspaces.However,youmayhaveexpectedforit tobenotindentedatall. Nico `}
我们可以用下面这个功能函数对生成的字符串进行处理已得到我们想要的结果:
functionunindent(text){ returntext .split('n') .map(line=>line.slice(4)) .join('n') .trim() }
不过,使用被称为标记模板的模板字符串新特性处理这种情况可能会更好。默认情况下,JavaScript会把解析为转义符号,对浏览器来说,以
开头的字符一般具有特殊的含义。比如说
n
意味着新行,u00f1
表示等等。如果你不想浏览器执行这种特殊解析,你也可以使用
String.raw
来标记模板。下面的代码就是这样做的,这里我们使用了String.row
来处理模板字符串,相应的这里面的n
没有被解析为新行。
vartext=String.raw`"n"istakenliterally. It'llbeescapedinsteadofinterpreted.` console.log(text) //"n"istakenliterally. //It'llbeescapedinsteadofinterpreted.
我们添加在模板字符串之前的String.raw
前缀,这就是标记模板,这样的模板字符串在被渲染前被该标记代表的函数预处理。一个典型的标记模板字符串如下:
tag`Hello,${name}.Iam${emotion}tomeetyou!`
实际上,上面标记模板可以用以下函数形式表示:
tag( ['Hello,','.Iam','tomeetyou!'],'Maurice','thrilled' )
我们还是用代码来说明这个概念,下述代码中,我们先定义一个名为tag
函数:
functiontag(parts,...values){ returnparts.reduce( (all,part,index)=>all+values[index-1]+part ) }
然后我们调用使用使用标记模板,不过此时的结果和不使用标记模板是一样的,这是因为我们定义的tag
函数实际上并未对字符串进行额外的处理。
varname='Maurice' varemotion='thrilled' vartext=tag`Hello,${name}.Iam${emotion}tomeetyou!` console.log(text)//
我们看一个进行额外处理的例子,比如转换所有用户输入的值为大写(假设用户只会输入英语),这里我们定义标记函数upper
来做这件事:
functionupper(parts,...values){ returnparts.reduce((all,part,index)=> all+values[index-1].toUpperCase()+part ) } varname='Maurice' varemotion='thrilled' upper`Hello,${name}.Iam${emotion}tomeetyou!` //
既然可以转换输入为大写,那我们再进一步想想,如果提供合适的标记模板函数,使用标记模板,我们还可以对模板中的表达式进行各种过滤处理,比如有这么一个场景,假设表达式的值都来自用户输入,假设有一个名为sanitize
的库可用于去除用户输入中的html标签,那通过使用标记模板,就可以有效的防止XSS攻击了,使用方法如下。
functionsanitized(parts,...values){ returnparts.reduce((all,part,index)=> all+sanitize(values[index-1])+part ) } varcomment='Evilcomment' varhtml=sanitized`${comment}`console.log(html) //Evilcomment
这篇文章主要介绍“JavaScript中的NaN怎么辨别”,在日常操作中,相信很多人在JavaScript中的NaN怎么辨别问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JavaScript中的NaN怎么辨别”的疑惑有所帮助!接…