+
运算符加号运算符如下几个功能:
注意:
1、在进行字符串拼接到时候要注意运算到顺序问题
2、在进行字符串拼接到时候要注意隐式转换问题
3、如果+
参与的运算里有对象,则会先调用valueOf()方法,如果不能转换为数值,再调用toString()
方法,其他原理与isNaN()一致;
1+{} // '1[object Object]'
1+{toString:function(){return 1;}} //2
1+{valueOf:function(){return 1},toString:function(){return 1;}} //2
1+{valueOf:function(){return 3},toString:function(){return 1;}} //4
1+{valueOf:function(){return {}},toString:function(){return 1;}} //2
-
运算符减号运算符有如下几个功能:
注意:
1、在进行减法运算法的时候需要注意隐式转换问题;
2、同样是对象操作的时候,会先调用valueOf(),在调用toString();
1-{} // 'NaN'
1-{toString:function(){return 1;}} // 0
1-{valueOf:function(){return 1},toString:function(){return 1;}} // 0
1-{valueOf:function(){return 3},toString:function(){return 1;}} // -2
1-{valueOf:function(){return {}},toString:function(){return 1;}} // 0
*
运算符*
号运算符有如下几个功能:
注意:
1、在进行乘法运算法的时候需要注意隐式转换问题
2、与上述同理
1*{} // 'NaN'
1*{toString:function(){return 1;}} // 1
1*{valueOf:function(){return 1},toString:function(){return 1;}} // 1
1*{valueOf:function(){return 3},toString:function(){return 1;}} // 3
1*{valueOf:function(){return {}},toString:function(){return 1;}} // 1
/
运算符/
运算符提供除法操作,提供基本的除法运算,返回结果是小数。
注意:
1、在进行除法运算法的时候需要注意隐式转换问题
2、与上述同理
1/{} // 'NaN'
1/{toString:function(){return 1;}} // 1
1/{valueOf:function(){return 1},toString:function(){return 1;}} // 1
1/{valueOf:function(){return 3},toString:function(){return 1;}} // 0.3333333333333333
1/{valueOf:function(){return {}},toString:function(){return 1;}} // 1
%
运算符%
运算符提供数学上取模运算或取余运算符。
注意:
1、在进行取余运算法的时候需要注意隐式转换问题
1%{} // 'NaN'
1%{toString:function(){return 1;}} // 0
1%{valueOf:function(){return 1},toString:function(){return 1;}} // 0
1%{valueOf:function(){return 3},toString:function(){return 1;}} // 1
1%{valueOf:function(){return {}},toString:function(){return 1;}} // 1
++
对变量进行自增加一操作,其等价于a+=1
或a=a+1
--
对变量进行自增加一操作,其等价于a-=1
或a=a-1
不论是++
还是--
,我们都需要考虑到++
或--
参与其他运算到时候,在前还是在后到运算顺序到问题,简而言之,在前的时候,先参与自增或自减运算,然后再参与其他运算,如果在后,先参与其他运算,在参与自增或自减运算。
不论是++
还是--
,都不能参与常量或字面量的运算,例如1++
这是一种错误的表达式,将会抛出如下错误;
ReferenceError: Invalid left-hand side expression in postfix operation
=
赋值运算符
a+=b
等价于a=a+b
a-=b
等价于a=a-b
a*= b
等价于a=a*b
a/=b
等价于a=a/b
a%=c
等价于a=a%b
所有按位操作对操作数都会被转换位补码形式都有符号32位整数,补码形式指的是一个数都负对应值位数值都所有都bit位反转再加1;
&
按位与操作是对每个bit位进行与操作,基本规则就是全1位1,否则位0;
|
按位或操作是对每个bit位进行与操作,基本规则就是全0位0,否则位0;
^
按位或操作是对每个bit位进行或操作,基本规则就是不相同为1,相同0
~
对每个bit位执行非操作,也就是对数求反码的操作
对于按位非操作,我们可以使用如下的操作形式,其性能较佳,但是不一定便于其他人理解
var str = 'rawr';
var searchFor = 'a';
// 这是 if (-1*str.indexOf('a') <= 0) 条件判断的另一种方法
if (~str.indexOf(searchFor)) {
// searchFor 包含在字符串中
} else {
// searchFor 不包含在字符串中
}
<<
左移n位,相当于乘以2的n次方
>>>
无符号右移:向右移出的位被丢弃,左侧用0填充,因为符号位变0了(0填充),所以结果总是非负数。
>>
有符号右移:向右移出的位被丢弃,拷贝最左侧以填充左侧,由于新的左侧位总是和以前相同,符号位没有被改变,所以被叫符号传播
可以简单理解:相当于除以2的n次方
位运算经常用来被创建、处理以及读取标志位序列——一种类似二进制的变量,虽然可以使用变量来代替标志位序列,但是这样可以节省内存(1/32)。
例如,有3个标志位,例如我们在linux系统之中,对文件有三种权限,我们可以采用一个3位对二进制数来表示,例如r位读权限,w位写权限,x位可执行权限。
标志位A Executable,可执行
标志位B:Writable,可写
标志位C:Readable ,可读
标志位通过位序列CBA来表示,当一个位被置位是,它位1,被清除时,他为0
var flags = 5; //0101; 所以这个值表示为有可读、可执行,不可写
因为位运算是32位对,0101实际上是00000000000000000000000000000101,因为前面多余对0没有意义,所以可以忽略
掩码(bitmask)是一个通过&
或|
来读取标志位对位序列,典型对定义每个标志位对原语掩码如下
var FLAG_EXECUTABLE = 1; // 0001
var FLAG_WRITABLE = 2; // 0010
var FLAG_READABLE = 4; // 0100
新的掩码可以在以上掩码上使用逻辑运算创建
var mask = FLAG_EXECUTABLE | FLAG_WRITABLE | FLAG_READABLE;
// 0001 | 0010 | 0100 => 111
某个特定对位可以通过与掩码与运算的到,通过与掩码对与运算可以去掉无关对位置
var flags = 5; //0101; 所以这个值表示为可读、可执行、不可写
if( flags & FLAG_READABLE){ // 0101 & 0100 => 0100 => true, 判断是否被置为可读
// do something
}
if ( ( flags & FLAG_READABLE) || ( flags & FLAG_WRITABLE))
// ( 0101 & 0100 ) || (0101 & 0100) => 0100 || 0000 => 0100 =>true 判断是否可读或可写
// do something
}
// 一下方法与上一个方法一样
if ( flags & ( FLAG_READABLE | FLAG_WRITABLE))
// ( 0101 & 0100 ) || (0101 & 0100) => 0100 || 0000 => 0100 =>true 判断是否可读或可写
// do something
}
我们可以通过与掩码做或运算(|
),进行设置标志位,将掩码对位设置对应对位,例如位们用掩码110来设置可读、可写;
var mask = FLAG_READABLE | FLAG_WRITABLE; // 0100 | 0010 => 0110
flags |= mask; // 0101 | 0110 => 0111 // 可读、可写、可执行
同样,我们也可以通过与掩码做清除标志位,掩码中位0对位可以设置对应的位,掩码可以通过原语掩码来做非运算取得(~
),例如我们使用001来设置不可写、不可读
var mask = ~( FLAG_READABLE | FLAG_WRITABLE) ; // ~110 =>001
flags &= mask; // 0101 | 0001 = 0001 => 可执行、不可读、不可写
// 根据德摩根定律如下代码与上述等价
var mask = ~FLAG_READABLE & ~FLAG_WRITABLE;
flags &= mask; // 0101 | 0001 = 0001 => 可执行、不可读、不可写
我们也可以使用异或运算(^)来切换标志位,例如使用掩码101来切换标志位可读和可执行
var flags = 4; // 可读
var mask = FLAG_WRITABLE | FLAG_EXECUTABLE; // 010 | 001=> 011
flags ^= mask; // 0100 ^ 011 = 011 => 可写、可执行
案例2:使用位运算来完成二进制转换(该代码位于mdn上)
function createBinaryString (nMask) {
// nMask must be between -2147483648 and 2147483647
for (var nFlag = 0, nShifted = nMask, sMask = ""; nFlag < 32;
nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1);
return sMask;
}
var string1 = createBinaryString(11);
var string2 = createBinaryString(4);
var string3 = createBinaryString(1);
==
(等于)与!=
(不等于)如果一个操作数是非数,一个操作数为数值的情况遵循以下规则
NaN
,则==
返回false
,!=
返回true
,NaN
有自身不等特性;注意:null
、undefined
在比较等于的时候不会自动转换;
===
与!==
1、全等于
全等于要求数据类型相等并且值也相等,如果类型不同,返回false
,如果类型相同,则判断值是否相同
2、不全等于
如果类型不同或值不同,返回true
,否则返回false
<
、<=
、>
、>=
比较规则:
1、如果关系运算符两边的算子都是number类型,则进行数值比较;
2、如果关系运算符两边的算子都是字符串类型,则进行ASCII码值比较;
3、如果只有一个字符串,一个是数值类型,则会转换为数值,再比较;
4、如果有一个是对象,则先调用valueOf()
方法或调用toString()
,如果这两个方法没有重写,返回false
;
5、返回值为布尔类型,true
或false
;
6、null
会自动转换为0, undefined
则不会,undefined
和任何数比较都是false
;
0>null // false
0>=null // true
0>{} //false
0>{toString:function(){return '1'}} // false
2>{valueOf: function(){return 2}} / false
3>{toString:function(){return '1'}} // true
4>{valueOf: function(){return 3}} // true
in
运算符in
运算符如果指定的属性在指定的对象或其原型链中,则in 运算符返回true
。其语法形式如下
prop in object
// prop 一个字符串类型或者 symbol 类型的属性名或者数组索引(非symbol类型将会强制转为字符串)。
// objectName 检查它(或其原型链)是否包含具有指定名称的属性的对象。
值的注意的一点,in判断的是属性,而不是属性值,如果属性被删除了将返回false
,如果你赋值为undefined
将返回true
(因为该属性存在,只是其值为undefined
),同时也能判断继承来的属性;
逻辑运算符通常用于布尔值都操作,一般和关系运算符配合使用,有三个逻辑运算符:逻辑与、逻辑或、逻辑非
&&
如果运算符两边有一个不是布尔值都情况,与运算符不一定返回布尔值,此时遵循如下规则
true
,才返回第二个操作数,否则返回false
;null
,则返回null
,针对第一个操作数为null
或第一个操作数为true
的情况;undefined
,则返回undefined
,针对第一个操作数为undefined
或第一个操作数为true
的情况;逻辑与采用短路运算规则,如果第一个为false
,则为false
,如果全为true
才为true
;
true && null // null
true && undefined // undefined
false && null //false
false && undefined //false
var a= {t:1};
a && false; // false
a && 123; // 123
true && a // { t: 1 }
false && a // false
||
如果运算符两边有一个不是布尔值都情况,或运算符不一定返回布尔值,此时遵循如下规则
false
,返回第二个操作数;null
,则返回null
;NaN
,则返回NaN
;undefined
,则返回undefined
;null
、undefined
或NaN
,则返回另一个操作数逻辑与采用短路运算规则,如果第一个为true
,则为true
,如果全为false
才为false
;
我们可以使用第七个特性来避免null
或undefined
,例如客户端JavaScript之中的事件对象event的浏览器兼容性问题,在IE/Opera中,是window.event
,而在Firefox中,是event
;
而事件的对象,在IE中是window.event.srcElement
,在Firefox中是event.target
,而在Opera中则两者都支持。
function test(event){
var event=window.event || event;
var objEle = event.target || event.srcElement; // 获取事件的document 对象的引用
}
!
逻辑非只有一个操作数,可以用于任何值,无论这个值是什么数据类型。它的流程就是先将这个值转换成布尔值,在取反;前面我们已经知道了下面如下几种情况返回false;
null
undefined
'"
或''
非真即假,非假即真,所以!true == false