CocosCreator_JavaScript权威指南(第六版)_第4章_表达式和运算符
表达式JavaScript中的⼀个短句,JavaScript解释器会将其计算(evaluate)出⼀个结果。程序中的常量是最简单的⼀类表达式。变量名也是⼀种简单的表达式,它的值就是赋值给变量的值。复杂表达式是有简单表达式组成的。⽐如,数组访问表达式是由⼀个表⽰数组的表达式、左⽅括号、⼀个整数表达式和右⽅括号构成。他们所组成的新的表达式的运算结果是该数组的特定位置的元素值。同样的,函数调⽤表达式由⼀个表⽰函数对象的表达式和0个或多个参数表达式构成。
将简单表达式组合成复杂表达式是最常⽤的⽅法就是使⽤运算符。运算符按照特定的运算规定对操作数进⾏运算,并计算出新值。乘法运算符“*”是⽐较简单的例⼦。表达式x*y是对两个变量表达式x和y进⾏运算并得出结果。有时我们更愿意说运算符返回了⼀个值⽽不是“计算”出了⼀个值。
4.1 原始表达式
最简单的表达式是“原始表达式”。原始表达式是表达式的最⼩单位–他们不再包含其他表达式。JavaScript中的原始表达式包含常量或直接量、关键字和变量。
直接量是直接在程序中出现的常数值。他们看起来像:
1.23(数字直接量)(3.1)
“hello”(字符串直接量)(3.2)
/pattern/(正则表达式直接量)(3.2.4、10)
JavaScript中的⼀些保留字构成了原始表达式:
true false null this
我们在3.3和3.4中学习了true、false和null。和其他关键字不同,this并不是⼀个常量,它在程序的不同地⽅返回的值也不相同。this关键字经常在⾯对对象编程中出现。在⼀个⽅法体内,this返回调⽤这个⽅法的对象。
最后,第三种原始表达式是变量:
i sum undefined(是全局变量,和null不同,他不是⼀个关键字)
当JavaScript代码中出现了标识符,JavaScript会将其当做变量⽽去查它的值。如果变量名不存在,表达式运算结果为undefined。然⽽,在ECMAScript 5的严格模式中,对不存在的变量进⾏求值会抛出⼀个引⽤错误异常。
4.2 对象和数组的初始化表达式
对象和数组初始化表达式实际上是⼀个新创建的对象好数组。这些初始化表达式有时称做“对象直接量”和“数组直接量”。然⽽和布尔直接量不同,他们不是原始表达式,因为它们所包含的成员或者元素都是⼦表达式。数组初始化表达式语法⾮常简单,我们以此开始,
数组初始化表达式是通过⼀对⽅括号和其内由逗号隔开的列表构成的。初始化的结果是⼀个新创建的数组。数组的元素是逗号分隔的表达式的值:
[]//⼀个空数组:[]内留空即表⽰该数组没有任何元素
[1+2,3+4]//拥有两个元素的数组,第⼀个是3,第⼆个是7
数组初始化表达式中的元素初始化表达式也可以是数组初始化表达式。也就是说,这些表达式是可以嵌套的:
var matrix =[[1,2,3],[4,5,6],[7,8,9]];
JavaScript对数组初始化表达式进⾏求值的时候,数组初始化表达式中的元素表达式也都会各⾃计算⼀次。也就是说,数组初始化表达式每次计算的值有可能是不同的。
数组直接量中的列表逗号之间的元素可以省略,这时省略的空位会天充值undefined。例如,下⾯这个数组包含5个元素,其中三个元素是undefined:
var sparseArray[1,,,,5];
数组直接量的元素列表结尾处可以留下单个逗号,这时并不会创建⼀个新的值为unidentified的元素。
对象初始化表达式和数组初始化表达式⾮常类似,只是⽅括号被花括号代替,并且每个⼦表达式都包含⼀个属性名和⼀个冒号作为前缀:var p ={x:2.3,y:-1.0};
对象直接量也可以嵌套,⽐如:
var p ={ upperLeft:{X:2,Y:2},
lowerRight:{X:4,Y:5}};
JavaScript求对象初始化表达式的值的时候,对象表达式也都会各⾃计算⼀次,并且它们不必包含常数值:它们可以是任意JavaScript表达式。同样,对象直接量中的属性名称可以是字符串⽽不是标识符(这在那些只能使⽤保留字或⼀些⾮法标识符作为属性名的地⽅⾮常有⽤):
var side = 1;
var square ={ "upperLeft":{x:p.x,y:p.y}
"lowerRight":{x:p.x+side,y:p.y+side}};
4.3 函数定义表达式
函数定义表达式定义⼀个JavaScript函数。表达式是值是这个新定义的函数。从某种意义上讲,函数定义表达式可称为“函数直接量”,毕竟对象初始化表达式也称为“对象直接量”。⼀个典型的函数定义表达式包含关键字function,跟随其后的是⼀对圆括号,括号内是⼀个以逗号分割的列表,列表含有0个或多个标识符(参数名),然后在跟随⼀个由花括号包裹的JavaScript代码段(函数体),例如:
var s = function(x){return x*x;}
4.4 属性访问表达式
属性访问表达式运算得到⼀个对象属性或⼀个数组元素的值。JavaScript为属性访问定义了两种语法:
expression.identifier
expression[expression]
第⼀种写法是⼀个表达式后跟随⼀个句号和标识符。表达式指定对象,标识符则指定需要访问的属性
的名称。第⼆种写法是使⽤⽅括号,⽅括号内是另外⼀个表达式(这种⽅法适⽤于对象和数组)。第⼆个表达式指定要访问的属性的名称或者代表要访问数组元素的索引。javascript全局数组
不管使⽤哪种形式的属性访问表达式,在“.”和“[”之前的表达式总是会⾸先计算。如果计算结果是null或者undefined,表达式会抛出⼀个类型错误异常,因为这两个值都不能包含任意属性。如果运算结果不是对象(或者数组),JavaScript会将其转换为对象(3.6)。如果对象表达式后跟随句点和标识符,则会查由这个标识符所指定的属性的值,并将其作为整个表达式的值返回。如果对象表达式后跟随⼀对⽅括号,则会计算⽅括号内的表达式的值并将它转换为字符串。不论哪种情况,如果命名的属性不存在,那么整个属性访问表达式的值就是undefined。
显然.identifier的写法更加简单,但需要注意的是,这种⽅式只适⽤于要访问的属性名称是合法的标识符,并且需要知道要访问的属性的名字。如果属性名称是⼀个保留字或者包含空格和标点符号,或是⼀个数字(对于数组来说),则必须使⽤⽅括号的写法。当属性名是通过运算得出的值⽽不是固定的值的时候,这时必须会⽤⽅括号写法(6.2.1)
4.5 调⽤表达式
JavaScript中的调⽤表达式是⼀种调⽤(或者执⾏)函数或⽅法的语法表⽰。它以⼀个函数表达式开始,这个函数表达式指代了要调⽤的函数。函数表达式后跟随⼀对圆括号,括号内是⼀个以逗号隔开
的参数列表,参数可以有0个也可有多个,例如:
f(0)//f是⼀个函数表达式;0是⼀个参数表达式
Math.max(x,y,z)//Math.max是⼀个函数;x,y,z是参数
a.sort()//a.sort是⼀个函数,它没有参数。
当对调⽤表达式进⾏求值的时候,⾸先计算函数表达式,然后计算参数表达式,得到⼀组参数值。如果函数表达式的值不是⼀个可调⽤的对象,则抛出⼀个类型错误异常(所有的函数都是可调⽤的,即使宿主对象不是函数它也有可能被调⽤)。然后。实参的值被依次赋值给形参,这些形参是定义函数时指定的,接下来开始执⾏函数体。如果函数使⽤returen语句给出了⼀个返回值,那么这个返回值就是整个调⽤表达式的值。否则,调⽤表达式的值就是undefined。函数调⽤–包括当形参表达式的个数和函数定义中实参的个数不匹配的时候的运⾏情况。
任何⼀个调⽤表达式都包含⼀对圆括号和左圆括号之前的表达式。如果这个表达式是⼀个属性访问表达式,那么这个调⽤称做“⽅法调⽤”。在⽅法调⽤中,执⾏函数体的时候,作为属性访问主题的对象和数组便是其调⽤⽅法内this的指向。这种特性使得在⾯向对象编程范例中,函数可以调⽤其宿主对象。(9)
并不是⽅法调⽤的调⽤表达式通常使⽤全局对象作为this关键字的值。然⽽在ECMAScript 5中,那些通过严格模式定义的函数在调⽤时将使⽤undefined作为this的值,this不会指向全局对象。(5.7.3)
4.6 对象创建表达式
对象创建表达式创建⼀个对象并调⽤⼀个函数(构造函数)初始化新对象的属性。对象创建表达式和函数调⽤表达式⾮常类似,只是对象创建表达式之前多了⼀个关键字new:
new Object()
new Point(2,3)
如果⼀个对象创建表达式不需要传⼊任何参数给构造函数的话,那么这对空圆括号是可以省略掉的:
new Object
当计算⼀个对象创建表达式的值时,和对象初始化表达式通过{}创建对象的做法⼀样,JavaScript⾸先创建⼀个新的空对象,然
后,JavaScript通过传⼊指定的参数并将这个新对象当做this的值来调⽤⼀个指定的函数。这个函数可
以使⽤this来初始化这个新创建对象的属性。那些被当成构造函数的函数不会返回⼀个值,并且这个新创建并被初始化后的对象就是整个对象创建表达式的值。如果⼀个构造函数确实返回了⼀个对象值,那么这个对象就作为整个对象创建表达式的值,⽽新创建的对象就废弃了。
4.7 运算符概述
JavaScript中的运算符⽤于算术表达式、⽐较表达式、逻辑表达式、赋值表达式等。
需要注意的是,⼤多数运算符都是有标点符号表⽰,⽽另外⼀些运算符则是由关键字表⽰的,⽐如delete和instanceof。关键字运算符和标点符号所表⽰的运算符⼀样都是正规的运算符,他们的语法都⾮常⾔简意赅。
4.7.1 操作数的个数
4.7.2 操作数类型和结果类型
4.7.3 左值
左值(lvalue)是⼀个古⽼的术语,它是指“表达式只能出现在赋值运算符的左侧”。在JavaScript中,变量、对象属性和数组元素均是左值。ECMAScript 规范允许内置函数返回⼀个左值,但⾃定义的函数则不能返回左值。
4.7.4 运算符的副作⽤
计算⼀个简单的表达式不会对程序的运⾏状态造成任何影响,程序后续执⾏的计算也不会受到该计算的影响。⽽有⼀些表达式则具有很多副作⽤,前后的表达式运算会相互影响。赋值运算符是最明显的⼀个例⼦:如果给⼀个变量过属性赋值,那么那些使⽤这个变量或属性的表达式的值都会发⽣改变。“++”和“–”递增和递减运算符与此类似,因为它们包含隐式的赋值。delete运算符同样有副作⽤:删除⼀个属性就像()给这个属性赋值undefined。
其他的JavaScript运算符都没有副作⽤,但函数调⽤表达式和对象创建表达式有些特别,在函数体或者构造函数内部运⾏了这些运算符并产⽣了副作⽤的时候,我们说函数调⽤表达式和对象创建表达式是有副作⽤的。
4.7.5 运算符优先级
PS:属性访问表达式和调⽤表达式的优先级要⽐表中列出的所有运算符都要⾼。例如;
typeof my.functions
尽管typeof是优先级最⾼的运算符之⼀,但typeof也是在两次属性访问和函数调⽤之后执⾏的。
实际上,如果你真的不确定你所使⽤的运算符的优先级,最简单的⽅法就是使⽤圆括号来强⾏指定运算次序。有些重要规则需要熟记:乘法和除法的优先级⾼于加法和减法,赋值运算的优先级⾮常低,通常总是最后执⾏的。
4.7.6 运算符的结合性
结合性指定了在多个具有同样优先级的运算符表达式中的运算顺序。
4.7.7运算顺序
b = a+a*a;
b = (a++)+a*a; // 2 5
只有在任何⼀个表达式具有副作⽤⽽影响到其他表达式的时候,其求值顺序才会和看上去有所不同。
4.8 算术表达式
在JavaScript中,所有的数字都是浮点型的,除法运算的结果也是浮点型,⽐如,5/2的结果是2.5。除数为0的运算结果为正⽆穷⼤或负⽆穷⼤。⽽0/0的结果为NaN,所有这些运算均不会报错。
%
5%2 =1
6.5%2.1=0.2
4.8.1 “+”运算符
⼆元加法运算符“+”可以对两个数字做加法,也可以做字符串连接操作:
1+2 =3
“x”+“y”=“xy”
“1”+“2”=“12”
加号的转换规则优先考虑字符串连接,
4.8.2 ⼀元算术运算符
var a = "1";
var b = (a++)+a;
console.log(b); //3 ⽽不是12
运算符和操作数之间不能有换⾏符。
4.8.3 位运算符
1<<5 = 100000 = 32
位运算符要求它的操作数是整数,这些整数表⽰位32为整型⽽不是64位浮点型。
移位运算符要求右操作数在0⾄31之间。
位运算符会将NaN、Infinity和-Infinity都转换为0。
按位操作符(Bitwise operators) 将其操作数(operands)当作32位的⽐特序列(由0和1组成),⽽不是⼗进制、⼗六进制或⼋进制数值。例如,⼗进制数9,⽤⼆进制表⽰则为1001。按位操作符操作数字的⼆进制形式,但是返回值依然是标准的JavaScript数值。
按位与(&)
只有两个操作数中相对应的位都是1,结果中的这⼀位才是1. 0x1234&0x00FF ==0x0034
按位或(|)
位运算符“|”对它的整型操作数逐位执⾏布尔或(OR)操作。如果其中⼀个操作数相应的位为1,或者两个操作数相应位都是1,那么结果中的这⼀位就为1。将任⼀数值 x 与 0 进⾏按位或操作,其结果都是 x。将任⼀数值 x 与 -1 进⾏按位或操作,其结果都为 -1。
console.log(12|03); //13
1100(12)
1110(13)
console.log(0x12|0x03);//19
0x12 =18
0x03 =3
0x13 =19
按位异或(^)
位运算符“|”对它的整型操作数逐位执⾏布尔异或(XOR)操作。异或是指第⼀个操作数为true或第⼆个操作数为true,但两者不能同时为true。如果两个操作数中只有⼀个相应位为1(不能同时为1),那么结果中的这⼀位就是1.例如(),0xFF00^0xF0F0 = 0x0FF0。实现基于16位进制。⼗进制数之间的按位异或只有在特殊的情况下才可以实现。例如100^10 = 110。
按位⾮(~)
位于⼀个整型参数之前,它将操作数的所有位取反。根据JavaScript中带符号的整数的表⽰⽅法,对⼀个值使⽤“~”运算符相当于改变它的符号并减⼀。
运算符“”
左移(<<)
进第⼀个操作数的所有⼆进制位进⾏左移操作。将⼀个值移动⼀位相当于乘以2,移动两位相当于乘以4,以此类推。
7<<2 = 28. 111 11100 右侧补零原则
带符号右移(>>)
与左移相反。
操作符会将第⼀个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。
7>>1 = 3 111 11
-7>>1 = -4 -111 -100(相当于⽤它除以2(忽略余数))
-15>>1 = -8 -1111 -1000
⽆符号右移(>>>)
运算符“>>>”和运算符“>>”⼀样,只是左边的⾼位总是填补0,与原来的操作符号⽆关,例如:
-1>>4 = -1 但是-1>>>4 = 0x0FFFFFFF.结果恒为268435455
4.9 关系表达式
关系运算符⽤于测试两个值之间的关系,根据关系是否存在⽽返回true或false。关系表达式总是返回⼀个布尔值,通常在if、white或者for 语句中使⽤关系表达式,⽤以控制程序的执⾏流程。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论