操作符
一元操作符
- 只能操作一个值的操作符叫做一元操作符。
递增递减操作符
- 和C/C++里一样,递增递减操作符都只是在一个分号”;”的表达式生命周期内产生作用和差异,无论是前置的操作符还是后置的操作符,在分号结束表达式的时候,操作符都会被解析运算并给出结果。
- 让我们来通过一些例子了解这些差异:
var age = 29;
var num = age++ + 2;
console.log(num); //31
console.log(age); //30
var age = 29;
var num= ++age + 2;
console.log(num); //32
console.log(age); //30
var age = 29;
var num = age-- + 2;
console.log(num); //31
console.log(age); //28
var age = 29;
var num= --age + 2;
console.log(num); //30
console.log(age); //28
从这里可以明显的看出来操作的位置关系的影响。
-
但是你却不知道这些操作符同样对其他类型有效!在遇到字符串是会先按照数值转换规则先将其转换为数字值的时候再执行加减操作;遇到布尔值会按照true和false值转换为1或0;对于对象时也要执行valueOf()等一套操作进行转换!详细的转换规则我再上一节的内容里已经解释的非常详细,点击跳转
所以我们也可以一下例子:
var s1 = "2";
var s2 = "z";
var b = false;
var f = 1.1;
var o = {
varlueOf: functon() {
return -1;
}
}
s1++; //值变成数值3
s2++; //值为NaN(not a number)
b++; //值变成数值1
f--; //值变成0.10000000000000000009(由于浮点舍入误差所致)
c--; //值变成-2
位操作符
在js中同样包含神奇的位操作符,由于这些操作符设计的进制之间的转换尤其是有无符号区别更甚,在这里我就不做详细解释,网上对于进制转换的教程一大堆!
在ECMAscript的机制中,对数值进行操作符运算的时候有如下步骤:
1. 先对数值进行64位的二进制转换;
2. 把64位的二进制数转换为32位数值再进行操作;
3. 再讲32位的运算后的数值返回为64位数值。
-
按位非(NOT)
按位非由波浪线(~)表示,执行按位非是获取数值的反码:
var num1 = 25; //0001 1001 数值2进制都是32位的,这里省略了前面的0
var num2 = ~num1; //11111111 11111111 11111111 1110 0110
console.log(num2); //-26
//负数的反码补码转换中又一个取反加一的步骤
-
按位与(AND)
用字符(&)表示,这个和逻辑与(&&)是有区别的,直接看真值表
数位值1 | 数位值2 | 结果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
var result = 25 & 3;
console.log(result); //1
但是不要以为着个与的操作是比较出的布尔值,如果这样认为,你就大错特错了!!!
25 = 00000000 00000000 00000000 0001 1001
3 = 00000000 00000000 00000000 0000 0011 -------------------------------------------
AND= 00000000 00000000 00000000 0000 0001
是不是觉得很神奇!
-
按位或(OR)
有操作符(|)表示,看真值表:
数位值1 | 数位值2 | 结果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
结果有1 就能1!
var result = 25 | 3;
console.log(result); //27
25 = 00000000 00000000 00000000 0001 1001
3 = 00000000 00000000 00000000 0000 0011 -------------------------------------------
OR = 00000000 00000000 00000000 0001 1011
是不是觉得很神奇!
-
按位异或(XOR)
有操作符(^)表示,相异为一,看真值表:
数位值1 | 数位值2 | 结果 |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
结果有1 就能1!
var result = 25 ^ 3;
console.log(result); //26
25 = 00000000 00000000 00000000 0001 1001
3 = 00000000 00000000 00000000 0000 0011 -------------------------------------------
XOR= 00000000 00000000 00000000 0001 1010
是不是觉得很神奇!
此外还有左移(<<),右移(>>),无符号右移(>>>)等,都是在二进制数值的基础上进行操作的!
布尔操作符
- 布尔操作作为判断条件里的重头,在语句中扮演着绝对的重要性!想if……else、while等等语句中尤为明显!
- 布尔操作符返回的值永远是一个Boolean值,所以,在比较时会对操作符两边的数据进行隐式的转换为布尔值!
逻辑非
- 逻辑非由(!)表示,逻辑非操作符有点特殊,因为它一般只有一个运算”对象”,在运算时,先将其转换为布尔值,然后再进行取反操作,遵循规则如下:
注意:以下操作是取反后的值!!!!!!!
1. 如果操作数是一个对象,则返回false;
2. 如果操作数是一个空字符串,则返回true;
3. 如果操作数是一个非空字符串,则返回false;
4. 如果操作数是0,则返回true;
5. 如果操作数是任意非0数值,则返回false,包括无限大(Infinity);
6. 如果操作数是NaN,返回true;
7. 如果操作数是undefined,返回true;
console.log(!false); //true
console.log(!"blue"); //false
console.log(!0); //ture
console.log(!NaN); //true
console.log(!""); //true
console.log(!12345); //false
当然,为了得到这个目标的真正的值,要么用Boolean()函数转换外,也可以用(!!)来转换!
console.log(!!false); //false
console.log(!!"blue"); //true
console.log(!!0); //false
console.log(!!NaN); //false
console.log(!!""); //false
console.log(!!12345); //true
逻辑与
逻辑与由两个和号(&&)表示,有左右两个操作数,真值表与操作符与(&)一样,不过却是返回的布尔值:
-
在两边都是布尔值操作数的情况下正常按照真值表的结果进行,那么又有一边不是布尔值呢?
- 如果第一个操作数是对象,则返回第二个操作数;
- 如果第二个操作数是对象,则只有在第一个操作数为true的时候才会返回该对象。
- 如果两个操作数都是对象,则返回第二个操作数;
- 如果第一个数是null,则返回null;
- 如果第一个数是NaN,则返回NaN;
- 如果第一个数是undefined,则返回undefined;
咦?怎么和自己想象的不一样,为啥在语句里都是布尔值呢?那是因为在语句的判断条件里,会自动的对这些值进行隐式的布尔转换,对上面的返回值都进行转换!
逻辑或
-
逻辑或由两个竖线(||)表示,如果两边的操作数都是布尔值,则按照真值表进行运算,如果有一个不是布尔值,则按照以下规则:
- 如果第一个操作数是对象,则返回对象;
- 如果第一个操作数的求值结果为false,则返回第二个操作数;
- 如果两个操作数都是对象,则返回第一个对象;
- 如果两个操作数都是null,则返回null;
- 如果两个操作数都是NaN,则返回NaN;
- 如果两个操作数都是undefined,则返回undefined;
逻辑操作符的短路特性
- 对于逻辑与和逻辑或两个操作符来说,值得非常注意的就是他们的短路特性了!一旦忽略他们的特性,则会在很多时候摸不着头脑!
-
逻辑与的短路特性
逻辑与(&&)遵循能在上一个数值的时候决定结果,绝对不会看下一个!,比如第一个操作数为false,就不会看第二个操作数!
var found=true;
var result=(found && someUndefinedVariable);
console.log(result);
//这里会发生错误,因为someUndefinedVariable并没有定义,而引用是不会在引擎中自动创建变量的!
var found=false;
var result=(found && someUndefinedVariable);
console.log(result); //false
//这里就不会发生错误了,因为第一个为false已经中断了后面的运算操作。
-
逻辑或的短路特性
逻辑或(||)的短路特性和逻辑与恰恰相反,它会在遇到true的时候停止,而不会去看后面的操作数结果!
var found=true;
var result=(found || someUndefinedVariable);
console.log(result); //true
//这里不会发生错误了,因为第一个为true已经中断了后面的运算操作。
var found=false;
var result=(found || someUndefinedVariable);
console.log(result);
//这里会发生错误,后面的someUndefinedVariable即使是个函数也不会被执行!
注意在比较与运算的时候注意操作数里对象或者函数的返回值哦!
那些年我们用烂了的操作符
- 什么是我们用烂了的操作符呢?就是传说中的加减乘除,大小等于!求模运算等等!认识他们都不重要,重要的是他们的优先级 点击查看吧
- 但是值得一提的是,在智能的js中,当然有不一样的地方啦!
智能的加与减
- 加法减法除了具有正常的运算功能外,还有字符操作的功能!
让我们先来看一看各自的不一样的特点!
-
对于加法
如果有一个操作数是字符串,则将另外的操作数转换为字符串并进行拼接!
如果又一个操作数是对象、数值或者布尔,则调用相应的toString方法,获得其字符串值,在应用字符串的规则。这里可以参照字符串的转换规则详细版
var result = 5 + "5";
console.log(result); //55
var num1 = 5;
var num2 = 10;
var message1 = "The sum of 5 and 10 is :" + num1 +num2;
console.log(message1); //The sum of 5 and 10 is : 510
var num1 = 5;
var num2 = 10;
var message2 = "The sum of 5 and 10 is :" + (num1 +num2);
console.log(message2); //The sum of 5 and 10 is : 15
-
对于减法
如果又一个操作数是字符串、布尔值、null或undefined等,先将其转换为number值,在执行减法计算数值转换规则Number()方法
如果又一个操作符是对象,则调用对象的valueOf方法取得该对象的数值。如果得到的值是NaN,则结果就是NaN,如果对象没有valueOf()方法,则调用toString()方法并将得到的字符串转换为数值。
var result1 = 5 - true; //4,true被转换成了1
var result2 = NaN - 1; //NaN
var result3 = 5 - ""; //5,""被转换成了0
var result4 = 5 - "2"; //3,"2"被转换成了2
var result5 = 5 - null; //5,null被转换成了0
语句
- js同样是一门五脏俱全的语言,它的控制语句也非常丰富!
语句之所以区别于函数,主要在于他们的作用域问题,我会在下一节详细解释作用域与声明提升的问题!
-
基本语句:
- 基本条件语句:if……else;
- 基本测试循环语句:for;
- 特殊测试语句:
- 前测试循环语句:while语句;
- 后测试循环语句:do-while语句;
- 基本控制语句:switch;
- 迭代自循环语句:for-in语句;
- 标签语句(或者说跳转语句):label语句;
对于前面3种语句每个语言用法都是爹妈生的孩子一个样,我就不解释多的!而后面这两种语句则是非常新奇!
for-in语句
- for-in语句看起来不一样,实际上换个说法大家可能就都认识了!在非直译式脚本语言中,大多有一个非常统一或者类似的称呼foreach(),没错,它和foreach是非常相似的,但是使用率依旧不高!因此,我在这里解释它的强大之处!
- 先来看它的结构:
for(property in expression){
statement;
}
那我们如何来使用呢?
var arr=[1,2,3,4,5,6];
for(var items in arr){
console.log(items);
}
/* 0 1 2 3 4 5 */
数组对打印相应下标
var arr={
"name":"lily",
"age":"18",
"height":"180cm"
};
for(var items in arr){
console.log(items);
}
/* name age height */
对象会打印相应属性,或者说key。
label语句
- 在语句中设置label标签来实现对应操作时达到跳转!
- 来看结构和用法:
label:statement
End:
for (var i = 0; i < 10; i++) {
if (i % 2 == 0) {
console.log("this is "+ i);
} else if (i == 5) {
break End;
}
}
/* this is 0 this is 2 this is 4 */
如果没有break End,循环应该正常执行打印到this is 8,但是label标签End使循环中断了执行!