javascript-第五章-表达式和运算符

第五章-表达式和运算符

1. 表达式

最简单的表达式可以是直接量或者变量名。例如:

1
2
3
4
5
1
‘javascript’
true
null
num

直接量表达式的值是直接量本身,变量表达式的值是变量存放的值或引用的值。

2. 运算符概述

有些运算符由标点符号表示+ -,有些是由关键字表示,delete /instanceof

P(运算符优先级) A(结合性:L/R) 运算符 运算数类型 所执行的操作
15 L . 对象,标识符 属性存取
L [] 数组,整数 数组下标
L () 函数,参数 函数调用
R new 构造函数调用 创建新对象
14 R ++ lvalue 先递增或后递增的运算(一元的)
R lvalue 先递减或后递减的运算(一元的)
R - 数字 一元减法(负)
R + 数字 一元加法)
R ~ 数字 按位取补码的操作(一元的)
R ! 布尔值 取逻辑补码的操作(一元的)
R delete lvalue 删除一个属性(一元的)
R typeof 任意 返回数据类型(一元的)
R void 任意 返回未定义的值(一元的)
13 L *,/,% 数字 乘法,除法, 取余运算
12 L +,- 数字 加法,减法运算
L + 字符串 连接字符串
11 L << 整数 左移
L >> 整数 带符号扩展的右移
L >>> 整数 带零扩展的右移
10 L <, <= 数字或字符串 小于或小于等于
L >, >= 数字或字符串 大于或大于等于
L instanceof 对象,构造函数 检测对象类型
L in 字符串,对象 检查一个属性是否存在
9 L == 任意 测试相等性
L != 任意 测试非相等性
L === 任意 测试等同性
L !== 任意 测试非等同性
8 L & 整数 按位与操作
7 L ^ 整数 按位异或操作
6 L ` ` 整数
5 L && 布尔值 逻辑与操作
4 L ` `
3 R ?: 布尔值、任意、任意 条件运算符
2 R = 任意 赋值运算
R *=,/=,%=,+=,-=,<<=,>>=,>>>=,&=, = 任意
1 L 任意 多重计算的操作

2.1 运算数的个数

一元运算符: -3 //取反
二元运算符: +
三元运算符: ?:

2.2 运算数的优先级

乘法和除法是优先与加法和减法执行的,赋值的操作优先级很低,几乎最后执行。用括号可以提高优先级。

2.3 运算数的结合性

L表示结合性从左到右,R表示结合性从右到左,一个运算符的结合性说明了优先级相等时执行操作的顺序。

3. 算术运算符

加法运算符(+):
运算符“+”可以对数字进行加法运算,也可以对字符串进行连接操作。如果一个运算数是字符串,那么另一个运算数会被转换成字符串,进行连接操作。如果“+”运 算符对一个运算数是对象,那么它会把对象转换成可以进行加法运算或者连接操作对数字或字符串,这一转换通过调用对象的valueOf()/toString()来执行的。

减法运算符(-):
把运算符“-”用于二元操作时,它将从第一个运算数减取第二个运算数。如果运算数是非数字的,会将它们转换成数字。

乘法运算符():
运算符“
”会把两个运算数相乘,如果运算数是非数字的,运算符“*”会将它们转换成数字。

除法运算符(/):
运算符“/”将用第一个运算数除以第二个运算数。如果运算数为非数字,则运算符“/”会将它们转为数字。除数为0的结果为正无穷或负无穷。0/0结果为NaN。

1
2
3
4/0 // Infinity
-4/0 //-Infinity
0/0 //NaN

模运算符(%):
模运算符计算的是第一个运算数对第二个运算数对模,即余数。如果运算数是非数字的,运算符“%”会将它们转换为数字。结果和第一个运算数符号相同。
5%2 // 1
-5%2 //-1
取模运算符也适用于浮点型数字。

一元减法运算符(-):
当“-”被用于一元操作前(一个运算数前),它将执行一元取反操作。如果运算数是非数字的,运算符“-”会将它们转换为数字

一元加法运算符(+):
var a = +10000;”+”什么都没做,只计算参数的值。对于非数字型的运算符,会将运算数转为数字,如果不能被转换,将返回NaN.
+’123’ //123
+’1we’ //NaN

递增运算符(++):
运算符“++”对唯一运算数进行递增操作,如果运算数为非数字,会转为数字。
i = 1; j = ++i; // i:2,j:2
i = 1; k = i++; //i:2, k:1
如果运算符位于运算数前,即先递增,然后用运算数增长后值计算。
如果运算符位于运算数后,即先运算,后递增,运算的是递增前的值。

递减运算符(–):
运算符“–”是对它惟一的数字运算数进行逆减操作的(如每次减1),这个运算数必须是一个变量、数组的一个元素或者对象的一个属性。如果该变量元素或属性的值不是数字,运算符“-”首先会将它转换成一个数字。和运算符“++”一样,运算符“-”的实际行为是由它相对于运算数的位置决定的。
如果它位于运算数之前,它就先减少运算数的值,并且返回减少后的运算数的直。如果它位于运算数之后,它将减少运算数的值,但是返回的却是没有减少的值。

4. 相等运算符

相等运算符“==”和等同运算符“===”用于计算两个值是否相等,根据结果返回布尔值。

4.1 相等运算符(==)和等同运算符(===)

“==”和“===”都用于检测两个值是否相等。这两个运算符都接受任意类型都运算数。“===”是等同运算符,它采用严格都同一性定义检测两个运算数是否相同。“==”是相等运算符,它采用比较宽松的同一性(允许类型转换)定义检测两个数是否相等。

判断===运算符比较的两个值是否完全相等:

  • 如果两个值的类型不同,它们就不相等.

  • 如果两个值是数字,而且值相同,那么除非其中一个或两个值都为NaN,否则它们是等同的。值NaN永远不会与其他任何值等同,包括它自身。可用全局函数isNaN()检测值是否是NaN。

    1
    NaN==NaN //false   NaN===NaN //false
  • 如果两个值是字符串,而且串中同一位置上字符完全相同,那么它们就是完全等同。如果字符串内容或长度不同,它们就不是等同的。

  • 如果两个值都是布尔值true或false,那么它们等同。

  • 如果两个值引用的是同一个对象,数组或函数,那么它们完全等同。如果它们引用是不同的对象,即使这两个对象具有完全相同的属性或具有完全相同的元素,它们也不等同。

    1
    var a = {};var b = a; var c = {}; var d = c; b == d; //false
  • 如果两个值都是null或undefined,那么它们完全相同。

    1
    null == undefined // true null === undefined //false 

判断==运算符比较的两个值是否相等:

  • 如果两个值具有相同的类型,判断两个值是否相同,如果相同就相等
  • 如果两个值类型不同,仍然有可能相等。
    • 如果一个值是null,另一个值是undefined,它们相等
    • 如果一个值是数字,另一个值是字符串,把字符串转为数字,再用转换后值比较。
    • 如果一个值是true,将它转换为1,再进行比较,如果是false,转换为0再比较
    • 如果一个值是对象,另一个值是数字或字符串,将对象转换为原始类型的值再进行比较。可以使用对象的toString()方法或valueOf()方法将对象转换为原始类型的值。javascript核心语言的内部类通常先尝试valueOf()转换,再尝试toString()转换,但对于Date类,则先执行toString()转换。不属于javascript核心语言的对象可以采用js实现定义的方式把自身转换为原始数值。
    • 其他的数值组合是不相等的。

如下代码是一个测试相等性的例子,带有类型转换: “1” == true ,true会先转换为1,字符串“1”会转为数字1,结果为true

4.2 不等运算符(!=)和不等同运算符(!==)

运算符(!=)和(!==)检测情况和(==)和(===)结果相反

5. 关系运算符

5.1 比较运算符

比较运算符用来确定两个值的相对顺序。包括:

  • 小于运算符(<)
    • 如果运算符<的第一个运算数小于它的第二个运算数,它计算的值就为true否则它计算的值为fa1se
  • 大于运算符(>)
    • 如果运算符>的第一个运算数大于它的第二个运算数,它计算的值就为true,否则计算的值为 false
  • 小于等于运算符(<=)
    • 如果运算符≤=的第一个运算数小于或等于第二个运算数,那么它计算的值就为true,否则计算的值为 false。
  • 大于等于运算符(>=)
    • 如果运算符>=的第一个运算数大于或等于第二个运算数,那么它计算的值就为true,否则计算的值为 false。

这些比较运算符的运算数可以是任意类型的,但是只能在数字和字符串上执行比较操作,所有不是数字或字符串的类型将会被转换为数字或字符串。比较和转换规则如下:

  • 如果两个运算数是数字或者都被转换成了数字,那么将采取数字比较。
  • 如果两个运算数是字符串或都被转换成了字符串,那么将作为字符串进行比较。
  • 如果一个运算数是字符串,或者被转换成了字符串,另一个运算数是数字,或者被转换成了数字,那么运算符将会把字符串转换为数字,执行数字比较。如果字符串不代表数字,它将会转换为NaN,比较结果是false。
  • 如果对象可以被转换为数字或字符串,那么将执行数字转换。例如,比较date对象,可以从数字角度比较。
  • 如果运算数都不能被转换为数字或字符串,那么结果返回false。
  • 如果某个运算数是NaN,或者被转换成了NaN,那么结果返回false。

5.2 in运算符

in运算符要求做不运算数是一个字符串,或可以被转为字符串,右边的运算数是一个对象或数组。

1
2
3
4
5
var point = { x:1, y:1}
“x” in point;//true
“y” in point;//true
“z” in point; //false
“toString” in point; //继承属性,true

5.3 instanceof运算符

instanceof要求左边运算数是一个对象,右边运算数是对象类的名字。所有对象都是Object类的实例

1
2
3
4
5
6
7
8
var d = new Date();
d instanceof Date; //true
d instanceof Object; //true
d instanceof Number; //false
var a = [1,2,3];
a instanceof Array; //true
a instanceof Object; //true
a instanceof RegExp; //false

如果instanceof运算符的左边不是对象,或者右边运算数是一个对象,而不是构造函数,他将返回false. 另外,如果它右边运算数不是一个对象,他将返回运行时错误。

6. 字符串运算符

有几个运算符在运算数是字符串时具有特殊的作用。
运算符“+”将连接两个字符串运算数:

1
“hello”+“ ”+“there”; //hello there

运算符<,<=,>,>=将通过比较两个字符串来确定它们顺序。比较采用字母顺序,基于unicode编码标准。所有Latin字母表的大写字母都位于小写字母之前(即小于)。
运算符+比较特殊,它给予字符串运算数的优先级比数字运算数高。如果该运算符的一个运算数是字符串,那么另一个将被转换为字符串。进行连接操作。另一方面,如果比较运算符的两个运算数都是字符串,将进行字符串比较;

1
2
3
4
5
6
7
1 + 2//加法:3
1”+ 2; //连接运算:“12”
1”+ 2//连接运算: “12”
11 < 3//数字比较运算: false
11” < “3”; //字符串比较运算; true
11” < 3//数字比较运算:“11”被转换为11,false,如果只有一个是字符串,那么js会把它转换为数字。
“one” < 3 //数字比较运算:“one”转换为NaN,false

7. 逻辑运算符

7.1 逻辑与运算符(&&)

当运算符&&的两个运算数都是布尔值时,它对这两个运算数执行布尔AND操作,即当且仅当它的两个运算数都是true时,它才返回true如果其中一个或两个运算数值为 false,它就返回 false。

这个运算符的实际行为比较复杂。首先,它将计算第一个运算数,也就是位于它左边的表达式。如果这个表达式的值可以被转换成 false(例如,左边运算数的值为null、0或 undefined),那么运算符将返回左边表达式的值。否则,它将计算第二个运算数,也就是位于它右边的表达式,并且返回这个表达式的值。

if( a == b) stop(); 等价于(a==b) && stop();

7.2 逻辑或运算符(||)

当运算符Ⅱ的两个运算数都是布尔值时,它对这两个运算数执行布尔或操作,即如果它的两个运算数中有一个值为为true(或者两个都为为true),那么它就返回为true。如果它的两个运算数值都为false、它就返回false.

虽然 || 运算符常用为布尔或运算符,但是它和&&运算符一样,行为是比较复杂的.首先,它要计算第一个运算数,即它左边的表达式的值.如果这个表达式的值可以被转换成是真的,那么它就返回左边这个表达式的值。否则,它将计算第二个运算数,即位于它右边的表达式,并且返回该表达式的值.

7.3 逻辑非运算符(!)

逻辑非运算符是一个一元运算符,它放在一个运算数之前。它用来对运算数对布尔值取反。对任意值x应用两次该运算符(即!!x)都可以将它转换为一个布尔值。

8. 逐位运算符

  • 按位与运算符(&)
    运算符&对它的整型参数逐位执行布尔AND操作只有两个运算数中相应的位都为1、那么结果中的这一位才为1。例如,0x1234 & 0x00FF=0×0034
  • 按位或运算符(|)
    运算符|对它的整型参数逐位执行布尔或操作。如果其中一个运算数中的相应位为%1或者两个运算数中的相应位都为1,那么结果中的这一位就为1。例如,9|10=11
  • 按位异或运算符(^)
    运算符^对它的整型参数逐位执行布尔异或操作.异或是指第一个运算数是true,或者第二个运算数是true,但是两者不能同时为true如果两个运算数中只有一个数的相应位为1(但不能同时为1),那么结果中的这一位就为1例如,9^10=3。
  • 按位非运算符(~)
    运算符~是个一元运算符,它位于一个整型参数之前,它将运算数的所有位取反.根据javascript中带符号的整数的表示方法,对一个值使用~运算符相当于改变它的符号并且减1例如,~0x0f = Oxfffff00或-16
  • 左移运算符(<<)
    运算符<<左移第一个运算数中的所有位移动的位数由第二个运算数指定,移动的位数应该是一个0到31的整数。例如,在表达式a<<1中,a的第一位变成了它的第二位,a的第二位变成了它的第三位,以此类推新的第一位用0来补充,舍弃第32位的值。将一个值左移1位相当于对它乘2,左移2位相当于对它乘4,以此类推。例如,7<<1=14
  • 带符号的右移运算符(>>)
    运算符>>右移第一个运算数中的所有位,移动的位数由第二个运算数指定,移动的位数应该是一个0到31的整数。舍弃右边移出的位,填补在左边的位由原运算数的符号位决定,以便保持结果的符号与原操作数一致。如果第一个运算数是正的,就用O填补结果的高位;如果第一个运算数是负的,就用1填补结果的高位。将一个值右移1位,相当于用2除它(丢弃余数)右移2位,相当于用4除它,以此类推。例如,7>1=3,-7>>1=-4
  • 用0补足的右移运算符(>>>)
    运算符>>>和运算符>一样,只是从左边移入总是0,与原运算数的符号无关。例如,-1>>4=-1,但是-1>>4=268435455(0x0fffffff0)

9. 赋值运算符

运算符=要求它左边对运算数是一个变量,数组的一个元素,或是对象的一个属性,右边的运算数是一个任意的值,任意类型。

9.1 带操作的运算符

运算符+=可以作用于数字和字符串,如果它的运算数是数字,执行加法运算和赋值操作,如果是字符串,将执行连接操作和赋值操作。还有-=,*=,&=等。

10. 其他运算符

10.1 条件运算符(?)

条件运算符是 JavaScript中惟一的三元运算符(带有三个运算数)有时就称它为三元运算符。这个运算符常被写为?:,但是在代码中它却不是这样的,因为这个运算符具有三个运算数,第一个位于?之前,第二个位于?和:之间,第三个位于:之后。可以用如下方式来使用它:

x>0 ? xy : -xy

条件运算符的第一个运算数必须是一个布尔值(或能够被转换为布尔值),通常它是一个比较表达式的结果。第二个和第三个运算数可以是任何类型的值。条件运算符的返回值是由第一个运算数的布尔值决定的。如果这个运算数的值为true,那么条件表达式的值就是第二个运算数的值。如果第一个运算数的值为 false,那么条件表达式的值就是第三个运算数的值。

10.2 typeof运算符

typeof是个一元运算符,放在一个运算数之前,这个运算数可以是任意类型的。它的返回值是一个字符串,该字符串说明了运算数的类型。

如果 typeof的运算数是数字、字符串或者布尔值,它返回的结果就是“number”、“string”或“boolean。对对象、数组和null,它返回的是“object。对函数运算数它返回的是“function”。如果运算数是未定义的,它将返回“undefined”

当 typeof的运算数是 Number、 String或 Boolean这样的包装对象时,它返回的是“object。此外,对Date和 RegExp对象,它也返回“object。对于那些不属于JavaScript核心语言,而是由 JavaScript嵌入的环境提供的对象, typeof的返回值是由实现决定的。但是,在客户端 JavaScript中, typeof对所有的客户端对象返回的都是“object”,这与它对所有核心对象的处理是一样的。

由于 typeof对所有的对象和数组类型返回的都是“object”,所以它只在区别对象和原始类型时才有用。要区别一种对象类型和另一种对象类型,必须使用其他的方法。例如instanceof运算符和 constructor属性.

10.3 对象创建运算符(new)

new运算符用来创建一个新对象,并调用构造函数初始化它。new是一个一元运算符,出现在构造函数的调用之前。它的语法如下:

new constructor(arguments)

constructor必须是一个构造函数表达式其后应该有一个用括号括起来的参数列表,列表中有零或多个参数,参数之间用逗号分隔。 JavaScript简化了该语法,即如果函数调用时没有参数,就可以省去括号这种简化了的语法只适用于运算符new.下面是一些使用new运算符的例子:

o=new Object; //此处省略了可选的括号

d=new Date();//返回一个表示当前时间的Date对象

c= new Rectangle(3.0.4.0,1.52.75);//创建 Rectangle类的对象
obj[i]=new constructors[i] ();

运算符new首先创建一个新对象,该对象的属性都未被定义接下来,它将调用特定的构造函数,传递指定的参数,此外还要把新创建的对象传递给关键字this这样构造函数就可以使用关键字this来初始化新对象.

10.4 delete运算符

delete运算符是个一元运算符,它将删除运算数所指定的对象的属性、数组元素或变量(注3)。如果删除操作成功,它将返回true,如果运算数不能被删除,它将返回 false。并非所有的属性和变量都是可以删除的,某些内部的核心属性和客户端属性不能删除,用var语句声明的变量也不能被删除。如果 delete使用的运算数是一个不存在的属性,它将返回true(令人吃惊的是, ECMAScript标准规定,当 delete运算的运算数不是属性、数组元素或变量时,它返回true.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var o = {x:1,y:2};
undefined
delete o.x
true
typeof o.x
"undefined"
delete o.x
true
delete o
false
delete 1
true
y = 1
1
delete y
true

delete所能影响的只是属性值,并不能影响这些属性引用的对象。

1
2
3
4
5
var my = new Object();
my.a = new Date();
my.b = my.a;
delete my.a;
console.log(my.b);//时间值 Mon Jan 11 2021 17:54:58 GMT+0800 (中国标准时间)

10.5 void运算符

void是一个一元运算符,它可以出现在任何类型操作数之前。这个运算符的用途比较特殊,它总是舍弃运算数的值,然后返回undefined这种运算符常用在客户端的 javascript:URL中。在这里可以计算表达式的值,而浏览器不会显示出这个值

例如,可以在HTML的标记中以如下方式使用void运算符:

1
<a href="javascript: void window.open () ">Open New Window</a>

void另一个用途是专门生成undefined值

10.6 逗号运算符(,)

逗号运算符非常简单。它先计算其左边的参数,再计算其右边的参数,然后返回右边参数的值。因此,如下的代码:

1
2
3
4
5
i=0,j=1,k=2
// 等价于
i=0;
j=1;
k=2;

这个奇怪的运算符只在个别环境中使用,一般是在只允许出现一个表达式的地方计算几个不同的表达式时才使用的。在实际应用中,逗号运算符只和for循环语句联合使用。

10.7 数组和对象存取运算符

运算符“.”左边是一个对象,右边是一个标识符
运算符“[]”用于存取数组元素,还可以存取对象的属性。

10.8 函数调用运算符()