犀牛书,4. Javascript表达式与操作符
- 表达式是一个可以被求值并产生一个值的Javascript短语
- 简单表达式构成复杂表达式,函数调用表达式由一个求值为函数对象的表达式和零或多个作为函数参数的表达式构成
- 操作符
- 简单表达式构成复杂表达式通常通过操作符进行实现,乘法操作符*
- 不使用操作符的表达式(如数组索引和函数调用)
4.1 主表达式(primary expression)
-
指独立存在,不再包含更简单表达式的表达式,最小单元。包括常量或字面量值、某些语言关键字和变量引用。(字面量是可以直接嵌入在程序中的常量)
-
js中的一些保留字也是主表达式
-
变量、常量或全局对象属性的引用(var声明的全局变量被实现为全局对象的属性,可通过globalthis引用)
1.23 //数值字面量 "hello" //字符串字面量 true //求值为布尔值true,是一个保留字 null //同上 this //同上 i //求值为变量i的值 undefined //全局对象undefined属性的值
-
当程序中出现任何独立的标识符时,js会假设他是一个变量、常量或全局对象的一个属性,并查询它的值。如果不存在该变量,查询不存在的变量会导致抛错ReferenceError
4.2 对象和数组初始化程序
-
对象和数组的初始化程序也是一种表达式,但他们不是主表达式,因为他们包含用于指定属性值或元素值的子表达式。
[1+2,3+4] //两个元素的数组,[3,7] let matrix = [[1,2,3],[4,5,6]] //嵌套数组
-
在数组字面量中省略逗号间的值可以包含未定义的元素,例如以下数组包含5个元素,其中3个未定义
let a = [1,,,,5] // a[1] = undefined
-
在数组初始化程序的最后一个表达式后跟一个逗号,不会创建一个未定义的元素(这一点可以通过数组的length方法进行验证),但访问最后一个表达式后面的索引则一定会返回undefined
let a = [1,,,,5] let b = [1,,,,5,] let c = [1,,,,5,,] a.length === b.length // ->true a.length === c.length - 1 // ->true
-
对象初始化程序与数组类似,只不过:[]改为了{},子表达式多了属性名和:
-
ES6中对象字面量可以嵌套
let a = { hh: {x1:1,x2:2}, kk: {y1:4,y2:3} };
4.3 函数定义表达式
-
函数定义表达式定义js函数,也是“函数字面量”。它由以下几部分组成:function关键字、位于括号中的零或多个标识符(参数名)、以及一个位于花括号中的js代码块(函数体)。
-
在ES6及之后版本可使用更为简洁的箭头函数语法。
// 这个函数返回传入值的平方 let square = function(x) {return x*x} // 箭头函数写法 let square1 = (x) => x*x let square2 = (x) => {return x*x}
4.4 属性访问表达式
-
属性访问表达式的值为对象属性或数组元素的值。js中定义了两种访问属性的语法:
expression.identifier array1[0]
-
第一种语法是表达式后跟句点和一个标识符,表达式指定对象,标识符指定属性名。
-
第二种语法是表达式(对象或数组)后跟位于中括号中的表达式,第二个表达式指定属性名或数组元素的索引。
let o = {x: 1, y: {z: 3}}; let a = [o, 4, [5, 6]]; o.x // ->1 o.y.z // ->3 o["x"] // ->1 a[1] // ->4 a[2]["1"] // ->6 a[0].x // ->1
-
无论哪种语法,位于 . 或 [ 之前的表达式都会先求值。如果求值结果为null或undefined,则表达式会抛出TypeError,因为他们两是js中不能有属性的两个值。
- 如果是第一种语法,则会对以该标识符的属性求值,求得的值会成为整个表达式的值。
- 如果是第二种语法,则方括号中的第二个表达式先会被求值并转为字符串,而后整个表达式的值就是以该字符串为属性名的属性的值。
- 任一语法下,如果属性名不存在,则会求得undefined
-
两种语法中,句点加标识符的更为简洁。但属性名中包含空格或标点字符,或者是一个数值(对于数组来说),则必须使用方括号的语法。例如:
// 只能用方括号的情况 let a = {"a b": 3, "a.b": 4} a["a b"] // ->3 a["a.b"] // ->4