JS 运算符和流程控制

一、操作符

1.一元操作符

自加自减操作符

前置型

执行前置递增和递减操作时,变量的值都是在语句被求值以前改变的 

var num1 = 2;
var num2 = 20;
var num3 = --num1 + num2; // 等于 21
var num4 = num1 + num2; // 等于 21

 

后置型

把递增操作符放在变量后面并不会改变语句的结果 

var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2; // 等于 22
var num4 = num1 + num2; // 等于 21

 

在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减 1 的操作。字
符串变量变成数值变量。
 在应用于一个不包含有效数字字符的字符串时,将变量的值设置为 NaN(第 4 章将详细讨论)。
字符串变量变成数值变量。
 在应用于布尔值 false 时,先将其转换为 0 再执行加减 1 的操作。布尔值变量变成数值变量。
 在应用于布尔值 true 时,先将其转换为 1 再执行加减 1 的操作。布尔值变量变成数值变量。
 在应用于浮点数值时,执行加减 1 的操作。
 在应用于对象时,先调用对象的 valueOf()方法(第 5 章将详细讨论)以取得一个可供操作的
值。然后对该值应用前述规则。如果结果是 NaN,则在调用 toString()方法后再应用前述规
则。对象变量变成数值变量

var s1 = "2";
var s2 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1++; // 值变成数值 3
s2++; // 值变成 NaN
b++; // 值变成数值 1
f--; // 值变成 0.10000000000000009(由于浮点舍入错误所致)
o--; // 值变成数值-2 

 

加和减操作符

一元加操作符以一个加号(+)表示,放在数值前面,对数值不会产生任何影响,

var num = 25;
num = +num; // 仍然是 25

不过,在对非数值应用一元加操作符时,该操作符会像 Number()转型函数一样对这个值执行转换

var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1 = +s1; // 值变成数值 1
s2 = +s2; // 值变成数值 1.1
s3 = +s3; // 值变成 NaN
b = +b; // 值变成数值 0
f = +f; // 值未变,仍然是 1.1
o = +o; // 值变成数值-1

一元减操作符主要用于表示负数

var num = 25;
num = -num; // 变成了-25

当应用于非数值时,一元减操作符遵循与一元加操作符相同的规则,最后再将得到的数值转换为负数 

var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1 = -s1; // 值变成了数值-1
s2 = -s2; // 值变成了数值-1.1
s3 = -s3; // 值变成了 NaN
b = -b; // 值变成了数值 0
f = -f; // 变成了-1.1
o = -o; // 值变成了数值 1

 

2.位操作符

暂略

3.布尔操作符

逻辑非(!)

无论这个值是什么数据类型,这个操作符都会返回一个布尔值。逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再对其求反

 如果操作数是一个对象,返回 false;
 如果操作数是一个空字符串,返回 true;
 如果操作数是一个非空字符串,返回 false;
 如果操作数是数值 0,返回 true;
 如果操作数是任意非 0 数值(包括 Infinity),返回 false;
 如果操作数是 null,返回 true;
 如果操作数是 NaN,返回 true;
 如果操作数是 undefined,返回 true。

alert(!false); // true
alert(!"blue"); // false
alert(!0); // true
alert(!NaN); // true
alert(!""); // true
alert(!12345); // false

同时使用两个逻辑非操作符,实际上就会模拟 Boolean()转型函数的行为

alert(!!"blue"); //true
alert(!!0); //false
alert(!!NaN); //false
alert(!!""); //false
alert(!!12345); //true

逻辑与(&&)

 

逻辑与操作可以应用于任何类型的操作数,而不仅仅是布尔值

如果第一个操作数是对象,则返回第二个操作数;
如果第二个操作数是对象,则只有在第一个操作数的求值结果为 true 的情况下才会返回该
对象;
如果两个操作数都是对象,则返回第二个操作数;
如果有一个操作数是 null,则返回 null
如果有一个操作数是 NaN,则返回 NaN
如果有一个操作数是 undefined,则返回 undefined

 

 如果第一个操作数是 false,则无论第二个操作数是什么值,结果都不再可能是true 了

var found = true;
var result = (found && someUndefinedVariable); // 这里会发生错误
alert(result); // 这一行不会执行

 

var found = false;
var result = (found && someUndefinedVariable); // 不会发生错误
alert(result); // 会执行( "false")

 

逻辑或

与逻辑与操作相似,如果有一个操作数不是布尔值,逻辑或也不一定返回布尔值

如果第一个操作数是对象,则返回第一个操作数;
如果第一个操作数的求值结果为 false,则返回第二个操作数;
如果两个操作数都是对象,则返回第一个操作数;
如果两个操作数都是 null,则返回 null
如果两个操作数都是 NaN,则返回 NaN
如果两个操作数都是 undefined,则返回 undefined

与逻辑与操作符相似,逻辑或操作符也是短路操作符。也就是说,如果第一个操作数的求值结果为
true,就不会对第二个操作数求值了

var found = true;
var result = (found || someUndefinedVariable); // 不会发生错误
alert(result); // 会执行( "true")

 

4.乘性操作符

乘法

var result = 34 * 56;

在处理特殊值的情况下,乘法操作符遵循下列特殊的规则:
 如果操作数都是数值,执行常规的乘法计算,即两个正数或两个负数相乘的结果还是正数,而
如果只有一个操作数有符号,那么结果就是负数。如果乘积超过了 ECMAScript 数值的表示范围,
则返回 Infinity 或-Infinity;
 如果有一个操作数是 NaN,则结果是 NaN;
 如果是 Infinity 与 0 相乘,则结果是 NaN;
 如果是 Infinity 与非 0 数值相乘,则结果是 Infinity 或-Infinity,取决于有符号操作数
的符号;
 如果是 Infinity 与 Infinity 相乘,则结果是 Infinity;
 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的
规则。

除法

var result = 66 / 11;

 如果操作数都是数值,执行常规的除法计算,即两个正数或两个负数相除的结果还是正数,而
如果只有一个操作数有符号,那么结果就是负数。如果商超过了 ECMAScript 数值的表示范围,
则返回 Infinity 或-Infinity;
 如果有一个操作数是 NaN,则结果是 NaN;
 如果是 Infinity 被 Infinity 除,则结果是 NaN;
 如果是零被零除,则结果是 NaN;
 如果是非零的有限数被零除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
 如果是 Infinity 被任何非零数值除,则结果是 Infinity 或-Infinity,取决于有符号操作
数的符号;

 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。

求余

var result = 26 % 5; // 等于 1

与另外两个乘性操作符类似,求模操作符会遵循下列特殊规则来处理特殊的值:
如果操作数都是数值,执行常规的除法计算,返回除得的余数;
如果被除数是无穷大值而除数是有限大的数值,则结果是 NaN
如果被除数是有限大的数值而除数是零,则结果是 NaN
如果是 Infinity Infinity 除,则结果是 NaN
如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;
如果被除数是零,则结果是零;
如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则

 

5.加性操作符

var result = 1 + 2;

如果有一个操作数是 NaN,则结果是 NaN
如果是 Infinity Infinity,则结果是 Infinity
如果是-Infinity -Infinity,则结果是-Infinity
如果是 Infinity -Infinity,则结果是 NaN
如果是+0 +0,则结果是+0
如果是0 0,则结果是0
如果是+0 0,则结果是+0
不过,如果有一个操作数是字符串,那么就要应用如下规则:
如果两个操作数都是字符串,则将第二个操作数与第一个操作数拼接起来;
如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接
起来。

如果有一个操作数是对象、数值或布尔值,则调用它们的 toString()方法取得相应的字符串值,
然后再应用前面关于字符串的规则。对于 undefined null,则分别调用 String()函数并取得字符
"undefined""null"

var result1 = 5 + 5; // 两个数值相加
alert(result1); // 10
var result2 = 5 + "5"; // 一个数值和一个字符串相加
alert(result2); // "55"
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + num1 + num2;
alert(message); // "The sum of 5 and 10 is 510"
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + (num1 + num2);
alert(message); //"The sum of 5 and 10 is 15"

 

减法

var result = 2 - 1;

如果两个操作符都是数值,则执行常规的算术减法操作并返回结果;
如果有一个操作数是 NaN,则结果是 NaN
如果是 Infinity Infinity,则结果是 NaN
如果是-Infinity -Infinity,则结果是 NaN
如果是 Infinity -Infinity,则结果是 Infinity
如果是-Infinity Infinity,则结果是-Infinity
如果是+0 +0,则结果是+0
如果是+0 0,则结果是0

如果是0 0,则结果是+0
如果有一个操作数是字符串、布尔值、 null undefined,则先在后台调用 Number()函数将
其转换为数值,然后再根据前面的规则执行减法计算。如果转换的结果是 NaN,则减法的结果
就是 NaN
如果有一个操作数是对象,则调用对象的 valueOf()方法以取得表示该对象的数值。如果得到
的值是 NaN,则减法的结果就是 NaN。如果对象没有 valueOf()方法,则调用其 toString()
方法并将得到的字符串转换为数值

var result1 = 5 - true; // 4,因为 true 被转换成了 1
var result2 = NaN - 1; // NaN
var result3 = 5 - 3; // 2
var result4 = 5 - ""; // 5,因为"" 被转换成了 0
var result5 = 5 - "2"; // 3,因为"2"被转换成了 2
var result6 = 5 - null; // 5,因为 null 被转换成了 0

 

6.关系操作符

小于(<) 、大于(>) 、小于等于(<=)和大于等于(>=)再应用上面的规则。这几个操作符都返回一个布尔值

var result1 = 5 > 3; //true
var result2 = 5 < 3; //false

如果两个操作数都是数值,则执行数值比较。
如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。
如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
如果一个操作数是对象,则调用这个对象的 valueOf()方法,用得到的结果按照前面的规则执
行比较。如果对象没有 valueOf()方法,则调用 toString()方法,并用得到的结果根据前面
的规则执行比较。
如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。

 

在比较字符串时,实际比较的是两个字符串中对应位置的每个字符的字符编码值。经过这么一番比较之后,再返回一个布尔值 

var result = "Brick" < "alphabet"; //true
var result = "23" < "3"; //true

 

在比较数值和字符串时,字符串都会被转换成数值,然后再以数值方式与另一个数值比较

var result = "23" < 3; //false

 

如果那个字符串不能被转换成一个合理的数值

var result = "a" < 3; // false,因为"a"被转换成了 NaN

 

任何操作数与 NaN 进行关系比较,结果都是 false

var result1 = NaN < 3; //false
var result2 = NaN >= 3; //false

 

7.相等操作符

相等和不相等

如果两个操作数相等,则返回 true ,两个操作数不相等,则返回 false

两个操作符都会先转换操作数(通常称为强制转型),然后再比较它们的相等性 

在转换不同的数据类型时的基本规则 :

如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false 转换为 0,而
true 转换为 1

如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类
型值按照前面的规则进行比较;
这两个操作符在进行比较时则要遵循下列规则。
null undefined 是相等的。
要比较相等性之前,不能将 null undefined 转换成其他任何值。
如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true。重要提示:
即使两个操作数都是 NaN,相等操作符也返回 false;因为按照规则, NaN 不等于 NaN
如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,
则相等操作符返回 true;否则,返回 false

 

 全等和不全等

除了在比较之前不转换操作数之外,全等和不全等操作符与相等和不相等操作符没有什么区别。全等操作符由 3 个等于号(===)表示,它只在两个操作数未经转换就相等的情况下返回 true

var result1 = ("55" == 55); //true,因为转换后相等
var result2 = ("55" === 55); //false,因为不同的数据类型不相等
var result1 = ("55" != 55); //false,因为转换后相等
var result2 = ("55" !== 55); //true,因为不同的数据类型不相等

 

***  null == undefined 会返回 true,因为它们是类似的值;但 null === undefined 会返回 false,因为它们是不同类型的值

 

8.条件操作符

var max = (num1 > num2) ? num1 : num2;

如果num1 > num2 为真,返回num1

如果num1 > num2 为假,返回num2

9.赋值操作符

如果在等于号(=)前面再添加乘性操作符、加性操作符或位操作符,就可以完成复合赋值操作

num += 10;
//相当于
num = num + 10;

 

 乘/赋值(*=);
 除/赋值(/=);
 模/赋值(%=);
 加/赋值(+=);
 减/赋值(=);
 左移/赋值(<<=);
 有符号右移/赋值(>>=)
 无符号右移/赋值(>>>=)

 

10.逗号操作符

使用逗号操作符可以在一条语句中执行多个操作

var num1=1, num2=2, num3=3;

 

在用于赋值时,逗号操作符总会返回表达式中的最后一项 

var num = (5, 1, 4, 8, 0); // num 的值为 0

虽然逗号的这种使用方式并不常见,但这个例子可以帮我们理解逗号的这种行为

 

二、流程控制

1.if语句

 

if (i > 25) {
alert("Greater than 25.");
} else if (i < 0) {
alert("Less than 0.");
} else {
alert("Between 0 and 25, inclusive.");
}

 

2.do-while语句

var i = 0;
do {
i += 2;
} while (i < 10);
alert(i);

 

3.while语句

var i = 0;
while (i < 10) {
i += 2;
}

 

4.for语句

var count = 10;
for (var i = 0; i < count; i++){
alert(i);
}

 

5.for in 语句

for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性

for (var propName in window) {
document.write(propName);
}

使用 for-in 循环来显示了 BOM window 对象的所有属性

6.label语句

使用 label 语句可以在代码中添加标签,当break label 或 continue label  会跳到标签位置

start: for (var i=0; i < count; i++) {
alert(i);
}

这个例子中定义的 start 标签可以在将来由 break continue 语句引用。加标签的语句一般都
要与 for
语句等循环语句配合使用

7.break和continue语句

break跳出本层循环

var num = 0;
for (var i=1; i < 10; i++) {
if (i % 5 == 0) {
break;
}
num++;
}
alert(num); //4

continue跳出本次循环

var num = 0;
for (var i=1; i < 10; i++) {
if (i % 5 == 0) {
continue;
}
num++;
}
alert(num); //8

 

配合label使用

var num = 0;
outermost:
for (var i=0; i < 10; i++) {
for (var j=0; j < 10; j++) {
if (i == 5 && j == 5) {
break outermost;
}
num++;
}
}
alert(num); //55

建议如果使用 label 语句,一定要使用描述性的标签,同时不要嵌套过多的循环

8.with语句

不建议使用

9.switch语句

switch (i) {
case 25:
alert("25");
break;
case 35:
alert("35");
break;
case 45:
alert("45");
break;
default:
alert("Other");
}
合并两种情形
switch (i) {
case 25:
/* 合并两种情形 */
case 35:
alert("25 or 35");
break;
case 45:
alert("45");
break;
default:
alert("Other");
}

 

var num = 25;
switch (true) {
case num < 0:
alert("Less than 0.");
break;
case num >= 0 && num <= 10:
alert("Between 0 and 10.");
break;
case num > 10 && num <= 20:
alert("Between 10 and 20.");
break;
default:
alert("More than 20.");
}

 

三、函数

定义函数

function sayHi(name, message) {
alert("Hello " + name + "," + message);
}

 调用函数

sayHi("Nicholas", "how are you today?");

ECMAScript 中的函数在定义时不必指定是否返回值

 

理解参数

ECMAScript 函数的参数与大多数其他语言中函数的参数有所不同。 ECMAScript 函数不介意传递进
来多少个参数,也不在乎传进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数,
在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数,而解析器永远不
会有什么怨言。之所以会这样,原因是 ECMAScript 中的参数在内部是用一个数组来表示的。函数接收
到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任
何元素,无所谓;如果包含多个元素,也没有问题。实际上,在函数体内可以通过 arguments 对象来
访问这个参数数组,从而获取传递给函数的每一个参数。
其实, arguments 对象只是与数组类似(它并不是 Array 的实例),因为可以使用方括号语法访
问它的每一个元素(即第一个元素是 arguments[0],第二个元素是 argumetns[1],以此类推),使
length 属性来确定传递进来多少个参数。在前面的例子中, sayHi()函数的第一个参数的名字叫
name,而该参数的值也可以通过访问 arguments[0]来获取。因此,那个函数也可以像下面这样重写,
即不显式地使用命名参数:

function sayHi() {
alert("Hello " + arguments[0] + "," + arguments[1]);
}
FunctionExample05.

这个重写后的函数中不包含命名的参数。虽然没有使用 name message 标识符,但函数的功能
依旧。这个事实说明了 ECMAScript 函数的一个重要特点:命名的参数只提供便利,但不是必需的。另
外,在命名参数方面,其他语言可能需要事先创建一个函数签名,而将来的调用必须与该签名一致。但
ECMAScript 中,没有这些条条框框,解析器不会验证命名参数。

 

通过访问 arguments 对象的 length 属性可以获知有多少个参数传递给了函数。下面这个函数会
在每次被调用时,输出传入其中的参数个数:

function howManyArgs() {
alert(arguments.length);
}
howManyArgs("string", 45); //2
howManyArgs(); //0
howManyArgs(12); //1

 

function doAdd() {
if(arguments.length == 1) {
alert(arguments[0] + 10);
} else if (arguments.length == 2) {
alert(arguments[0] + arguments[1]);
}
}
doAdd(10); //20
doAdd(30, 20); //50

 

没有重载

 如果在 ECMAScript 中定义了两个名字相同的函数,则该名字只属于后定义的函数

function addSomeNumber(num){
return num + 100;
}
function addSomeNumber(num) {
return num + 200;
}
var result = addSomeNumber(100); //300

 

posted @ 2017-07-02 19:08  富坚老贼  阅读(202)  评论(0编辑  收藏  举报