多重含义指的是在开发人员看来是不清晰、不直观的代码。
JavaScript 会通过一套语法规则、优先级算法以及系统机制来处理这些「多重含义」的代码,把「多重含义」的代码变成「确定含义」,接下来我们讨论一下,都有哪些运算符存在多重含义。
加号+的多重含义
单个加号「+」作为运算符在 JavaScript 中有三种作用:
它可以表示字符串的连接
var str = 'hello' + 'world';
或者表示数字取正值的一元运算符
var n = 10;
var n2 = +n;
再或者表示数值的求和运算
var n = 100;
var n2 = n + 1;
在这三种表示中,字符串连接和数字求和是非常容易理解出多重含义的,因为 JavaScript 对于这两种运算的处理会依赖于数据类型检测
a = a + b;
所以它是无法知道真实的含义是在求和还是在做字符串连接。
在计算机规则里:如果表达式中存在字符串,则优先按字符串连接进行运算。
由于加号进行的是值运算,当参与运算时会调用方法 x.valueOf() 来确定操作数的类型,如果它的类型不符合要求,则会调用 x.toString() 再次尝试,这样复杂的类型转换逻辑,实际运算的结果会变得非常难以预测 …
不过这也是 JavaScript 在动态语言方面的特性,也就是所谓的动态绑定。
括号()的多重含义
最常见的形式就是作为函数声明里面的参数列表,通过括号传入参数。
function foo(v1, v2){}
而 new 关键字用于创建一个对象实例,并用括号来调用该构造器函数。
var myArray = new Array('abc',1)
它也可以在 with、for、if、while、do…while 等语句里面来作为限定元素,当 if、while、do…while 这几个语句时,括号”()“会将表达式结果转换成布尔值。
括号”()”还可以用于强制表达式运算,就是我们通常说的强制运算符优先级。
var abc = a * (b / c)
还可以作为函数和方法调用运算符
foo()
函数调用过程中括号“()”是运算符,当括号()作为运算符的时候,他只作用于表达式运算而不可能作用于语句。
function foo(){
return (1+2);
}
冒号:的多重含义
声明对象字面量的成员和声明标签
//声明对象字面量成员
var obj = {
value: 100,
foo: function(){}
}
//标签声明
myLabel: {}
以及在 switch 语句中声明一个分支
switch (obj){
case X : break;
}
它还有一个运算符的含义,在“?:”三元表达式中表示条件为 false 的表达式分支
X ? 'yes' : 'no'
大括号{}的多重含义
在所有的场景中,他都是作为语法/词法符号来使用的。
语句块
myLabel: {
//...
}
if(){
//...
}else{
//...
}
声明对象字面量
var obj = {
x: 1,
y: 2,
z: 3
}
函数声明
声明函数字面量的语法符号
foo = function(){
//...
}
结构化异常
大括号在结构化异常中是语法符号
try{
//...
} catch (exception){
//...
} finally {
//...
}
模板字符串
var abc = 'hello'
var code = `${abc}, world!`
模板被声明为字面量,在引擎正式执行代码之前完成解析,在 JavaScript 中的语法中 ${…}用来表示一个表达式。
解构赋值
从语法设计的角度上来讲,解构赋值表达式左侧的运算数是一个引用,而右侧是一个值。
将右侧的结果复制给左侧的引用来存储,如果左侧的被引用对象没有存储能力,这抛出异常。
let { x, y } = { 1, 2 }
在执行期,JavaScript 引擎将左侧的赋值模板视为一个内部结构,该结构表达了一组名字与它们的值之间的处理关系。
逗号,的多重含义
逗号,既可以是语法,又可以是运算符。在它作为连续运算符使用的时候,其效果表达式并返回结果值
a = (1, 2, 3)
该表达式是三个单值表达式的连续运算,其结果是最后一个表达式,也就是数字3,如果这里没有括号来调整优先级,那么按默认优先级会先完成赋值运算,就是将变量 a 赋值为 1。
// 语法解析期出错
var a = 1,2,3;
这是因为逗号,被解析成了语句 var 声明时用来分割多个变量的语法分隔符,而不是连续运算符。
方括号[]的多重含义
var table = [1, 2, 3]
var table_cell = table[1]
方括号可以被理解成数组声明,或者下标存取,还可以被理解成对象成员的存取。
这篇文章不是为了炫技能,在计算机系统里会存在多重含义的代码块,需要我们仔细分辨出来,如果某些细节没有理解,那在代码也许会得到有趣的结果。
题图生成于:Stable Diffusion
内容来源于《JavaScript 语言精髓与编程实战》。
如果您对本篇文章中提到的问题有任何疑问或想法,请在评论区留言,我将尽力回复。
微信公众号「小道研究」,获取更多关于前端技术的深入分析和实践经验。