JavaScript 运算符的多重含义

126 阅读4分钟

多重含义指的是在开发人员看来是不清晰、不直观的代码。

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 语言精髓与编程实战》。

如果您对本篇文章中提到的问题有任何疑问或想法,请在评论区留言,我将尽力回复。

微信公众号「小道研究」,获取更多关于前端技术的深入分析和实践经验。