JavaScript语法 第三章

JavaScript 语法

三、表达式和运算符

表达式是JavaScript中的一个短语,JavaScript解释器会将其计算出一个结果。程序中的常量是最简单的一类表达式。变量名也是一种简单的表达式,它的值就是赋值给变量的值。复杂表达式是由简单表达式组成的。比如,数组访问表达式是由一个表示数组的表达式、左方括号、一个整数表达式和右方括号构成。它们所组成的新的表达式的运算结果是该数组的特定位置的元素值。同样的,函数调用表达式由一个表示函数对象的表达式和0个或多个参数表达式构成。

3.1原始表达式

最简单的表示式是"原始表达式"。原始表达式是表达式的最小单位-它们不在包含其他表达式。JavaScript中的原始表达式包含常量或直接量,关键字和变量

直接量是直接在程序中出现的常数值。例如

1.23      // 数字直接量
"hello"   // 字符串直接量
/patern/  // 正则表达式直接量

JavaScript中的一些保留字构成了原始表达式。

true     // 返回一个布尔值:真
false    // 返回一个布尔值:假
null     // 返回一个值:空
this     // 返回"当前"对象

this并不是一个常量,他在程序的不同位置返回的值也是不同的。this关键字经常在面向对象编程中出现。

第三种原始表达式是变量

 i         // 返回变量i的值
sum       // 返回sum的值
undefined // undefined是全局变量和null不一样,他不是一个关键字

当JavaScript代码中出现了标识符,JavaScript会将其当作变量而去查找它的值。如果变量名不存在,表达式运算结果为underfined。

3.2 对象和数组的初始化表达式

对象和数组初始化表达式实际上是一个新创建的对象和数组。这些初始化表达式有时称作”对象直接量”和“数组直接量”。然而和布尔直接量不同,他们不是原始表达式。因为他们包含的成员或者元素都是子表达式。

数组初始化表达式是通过一对方括号和其内由逗号隔开的列表构成的。初始化的结果时一个新创建的数组。数组的元素时逗号分隔的表达式的值。

[]   // 一个空数组:[]内留空即表示该数组没有任何元素
[1+2,3+4]  // 拥有两个元素的数组,第一个时3,第二个是7

1)数组的初始化表达式中的元素初始化表达式也可以是数组初始化表达式。也就是说,这些表达式时可以嵌套的。

2)数组直接量中的列表逗号之间的元素可以省略,这是省略的空位会填充值undefined的元素。若在数组直接量的元素列表结尾处可以留单个逗号,此时并不会创建一个新的值为undefined的元素

var x=[[1,2,3],[4,5,6],[7,8,9]]; //数组的嵌套
var x=[1,,,,,,5]; //省略列表逗号的元素

对象初始化表达式和数组初始化表达式非常相似,只是方括号被花括号替代,并且每个子表达式都包含一个属性名和一个冒号作为前缀。

var p={x:2,y:-1.2}; //一个拥有两个属性成员的对象
var q={};          // 一个空对象

1)对象直接量也可以嵌套

2)JavaScript求对象初始化表达式的值的时候,对象表达式也都会各自计算一次,并且他们不必包含常数值,他们可以时任意的JavaScript表达式。同样,对象直接量中的属性名称也可以时字符串而不是标识符。

3.3 函数定义表达式

函数定义表达式定义一个JavaScript函数。表达式的值是这新定义的函数,从某种意义来讲,函数定义表达式可称为“函数直接量”,毕竟对象初始化表达式也称为“对象直接量”。一个典型的函数定义表达式包含关键字function,随后是一对圆括号,括号被是一个以逗号分割的列表,列表含有0个或者多个标识符(参数名),然后子啊跟随一个由花括号包裹的JavaScript代码段(函数体)。

var s=function(x){ retrun x*x;}  //这个函数返回传入参数值的平方
3.4 属性访问表达式

属性访问表达式运算得到一个对象属性或一个数组元素的值。JavaScript为属性访问定义了两种语法:

s.x
s[x]

第一种写法是一个表达式后跟随一个句号和标识符。表达式指定对象,标识符则指定需要访问的属性名称。第二种写法是使用方括号,方括号是另外一个表达式(这种方法适用于对象和数组)。第二个表达式指定要访问的属性的名称或者代表要访问数组元素的索引

var s={x:1,y:z{3}}  // 一个示例对象
s.y.z               // =>3:表达式s.y的z属性
s.x                 // =>1:表达式s的属性
s["x"]             // =>1:对象s的x属性
3.5调用表达式

JavaScript的调用表达式时一种调用函数或方法的语法表示。它以一个函数表达式开始,这函数表达式代指了需要调用的函数。函数表达式后跟随一对圆括号,括号内是一个以逗号隔开的参数列表,参数可以有0个或者多个。例如

f(0)         // f是函数表达式,0 是一个参数表达式
a.sort()     // a.sort()是一个函数,他没有参数

当对调用表达式进行求值的时候,首先计算函数表达式,然后计算参数表达式,得到一组参数值。如果函数表达式的值不是一个可以调用的对象,则抛出一个类型错误异常。然后,实参的值会一次赋值给形参,这些形参是你定义函数时指定的,接下来开始执行函数体。如果函数使用return语句给出一个返回值,那么这返回值就是整个调用表达式的值。否则,调用表达式的值就是underfined。函数调用-包括当形参表达式的个数和函数定义中实参的个数不匹配的时候的运行情况。

3.6对象创建表达式

对象创建表达式

创建一个对象并调用一个函数初始化对象的属性,对象创建表达式和函数调用表达式非常类似,只是对象创建表达式之前多了一个关键字new。

new Object();
new Point(2,3);
// 如果一个对象创建表达式不需要传入任何个参数给构造函数的话,那么这对空圆括号时可以省略的

当计算一个对象创建表达式的值时,和对象初始化表达式通过{}创建对象的做法一样,JavaScript首先创建一个新的空对象,然后,JavaScript通过传入指定的参数并将这新对象作为this的值来调用一个指定的函数,这个函数可以使用this来初始化这个新的创建对象的属性。那写呗当作构造函数不会返回一个值,并且这个新创建并被出书画后的对象就是整个对象创建表达式的值。如果一个构造函数确实返回了一个对象值,那么这个对象就作为整个对象创建表达式的值,而新创建的对象就废弃了。

3.7 运算符概括

3.7.1 运算符优先级

运算符优先级控制着运算符的执行顺序。优先级高的运算符的执行总是先于优先级低的运算符。

w=x+y*z;
//乘法运算符"*"比加法运算符"+"具有更高的优先级,使用乘法先执行,加法后执行。然后,由于赋值运算符"="具有最低的优先级,因此赋值操作是在右边的表达式计算出结果后进行的

JavaScript运算符优先级

 

 

 

<!-- L指从左至右的结合,R指从右至左结合,集合性指定了在多个具有同样优先级的元素安抚表达式中的于是暖顺序。从左至右是指运算符的执行是按照从右到左的顺序进行-->

w=x-y-z;      //和w=((x-y)-z); 是一样的
3.8算术表达式

本章节涵盖了那些进行算术计算的运算符,以及对操作数的计算操作。乘法,除法和减法运算符非常简单,加法独占一节,因为加法同样可以做字符串连接操作,比较特殊。

3.8.1 其他运算符

运算符”/“:用第二个操作数来出第一个操作数,因为JavaScript所有的数字都是浮点型的,触发运算符的结果也是浮点数,比如5/2的结果是2.5,而不是2。除数为0的运算结果为正无穷或者负无穷大,而0/0的结果是NaN。

运算符”%“:计算的是第一个操作数对第二个操作数的模。也就就是说第一个操作数除以第二个操作数的余数。结果的符号跟第一个操作数(被除数)和符号保持一致。例如5%2结果是1,-5%2的结果是-1。

3.8.2 ”+“运算符

二元加法运算符”+“,可以对两个数字做加法,也可以做字符串连接操作。

1 + 2     // =>3
"HELLO"+""+"there"  // =>"HELLO there"
"1"+"2"     // =>"12"
"1"+2       // =>"12":数字转换为字符串后进行字符串连接

加法的转换规则优先考虑字符串转换,如果其中一个操作数是字符串或者转换为字符串的对象,另外一个操作数将就会转换为字符串,加法将进行字符串的连接操作,如果两个操作数都不是类字符串,那么都将进行算术加法运算。

需要注意的是,当加法运算符和字符串和数字一起使用时,需要考虑加法的结合性的对运算顺序的影响,也就是说,运算结果是依赖于运算符的运算顺序。

1+2+"bind me"    // =>"3 bind me"
1+(2+"wer")      // =>"12wer"

3.8.2 一元算术运算符

一元运算符的作用一个单独的操作数,并产生一个新的值。在JavaScript中,一元运算符具有很高的优先级,并且都是右结合。

(1)一元加法(+)

一元加法运算符把操作数转换为数字,并返回这转换后的数字。如果操作数不本身就是数字,则直接返回这个数字

(2) 一元减法(-)

当减法作为一元运算符的时候,他会根据需要把操作数转换为数字,然后改变运算结果的符号

(3)递增(++)

递增“++”运算符对其操作数进行增量操作,操作数是一个左值,运算符将操作数转换为数字,然后给数字加1,并将加1后的数值重新赋值给表变量、数组元素或者对象属性

var i=1,u=++i; // i和u都是2 前增量,先进行增量计算,在返回值
var i=1,j=i++; // i是2,u=1 后增量,先返回值,在进行增量计算

(4)递减(--)

和“++”运算符的用法类似。它把操作数转换为数字,然后减1,并将计算后的值重新赋值给操作数。同样具有前增量和后增量的不同。

3.8.3 位运算符

位运算符可以对由数字表示的二进制数据进行更底层级的按位运算。

(1)按位与(&)

位运算符“&”对它的整型操作数逐位执行布尔与(AND)操作。只有两个操作数中相对于的位都是1,结果中这一位才是1。例如:0x1234 & 0x00FF=0x0034

(2)按位或(|)

位运算符“|“对它的整型操作数逐位执行布尔或(OR)操作。其中一个操作相应的位为1,或者两个操作数对应位都是1,那么结果中这一位就是1。例如:0x1234 | 0x00FF=0x12FF

(3)按位异或(^)

位运算符“|“对它的整型操作数逐位执行布尔异或(XOR)操作。异或是指第一个操作数位true或者第二个操作数位true,但是两个不能同时位true。如果两个操作只有一个相应位位1(不能同时位1),那么结果中的这一位就是1。例如:0xFF00 ^ 0xF0F0 =0XoFFo

(4)按位非(~)

运算符”~“是一元运算符,位于一个整型参数之前,他将操作数的所有位取反。例如: ~0xoF =-16

(5)左移(<<)

将第一个操作数的所有二进制位进行左移操作,移动的尾数由第二个操作数指定,移动的位数是0~31之间的一个整数。将一个值左移一位相当于它乘以2,左移两位相当于乘以4,以此类推。例如:7<<2=7*(2**2)=28

(6)右移(>>)

运算符”>>“将第一个操作数的所有位进行右移操作,移动的尾数由第二个操作数指定,移动的位数是0~31之间的一个整数。右边溢出的位将忽略。填补在左边的位由原操作数的符号决定,以便保持结构的符号于原操作数一致。如果第一个操作数是整数,移位后用0填补最高位。如果第一个操作数是负的,移位后用1填补高位。将一个值右移1位,相当于用它除以2(忽略余数),右移两位,相当于它除以4,以此类推。例如:7>>1=3,-7>>1=-4

3.9表达式计算

和其他很多解释性语言语言,JavaScript同时可以解释运行由JavaScript源代码组成的字符串,并产生一个值。JavaScript通过全局函数eval()来完成这个工作。eval()是一个函数!!!

eval ("3+2")    // => 5

3.9.1 eval()

eval()只有一个参数。如果传入的参数不是字符串,他将直接返回这个参数。如果参数是字符串,他将会把字符串当作JavaScript代码进行编译。如果编译失败则抛出一个语法错误异常。如果编译成功,则开始执行这段代码,并返回字符串中的最后一个表达式或语句的值,如果最后一个表达式或者语句没有值,则最总返回undefined。如果字符串抛出一个异常,这个异常将把该调用传递给eval()。

需要注意的是,它使用了调用它的变量作用域环境,也就是说,它查找变量的值和定义新变量和函数的操作和局部作用域中的代码完全一样。如果它定义了一个局部变量x,然后调用eval("x"),,他会返回局部变量的值。如果在最顶层代码中调用eval(),他将会作用于全局变量和全局函数。

eval("function f(){ return x+1;}")

3.9.2 全局eval()

当通过别名调用时,eval()会将其字符串当作顶层的全局代码来执行,执行的代码可能会定义新的全局变量和全局函数,或者给全局变量赋值,但却不能使用或修改主调函数中的局部变量。

var s=eval;                 //使用别名调用eval将是全局eval
var x='global',y='global';  // 定义两个全局变量
function f(){ // 函数内执行的数局部eval
var x='local'; // 定义局部变量  
eval("x+'changed';");   // 直接eval更改了局部变量的值
return x; // 返回更改后的局部变量
}
console.log(f(),x);   // 更改了局部变量,输出'local changed global';

 

posted @   食尸之鬼  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
点击右上角即可分享
微信分享提示