操作符
一元操作符
-递增:
前置型 => ++a => 语句求值前先自加
后置型 => a++ => 语句求值后再自加
-递减:
前置型 => --a => 语句求值前先自减
后置型 => a-- => 语句求值后再自减
可以应用于非数值类型:
字符串:转换成数值后进行递增/递减,采用Number方法,不能转换成数值的转换成NaN
布尔:转换成数值后进行递增/递减,false0,true1
对象:采用Number方法规则

-一元加:
数值:对值无影响
其它类型:Number转换成数值
-一元减:
数值:变负
其它类型:Number转换成数值后变负
位操作符
按内存中表示数值的位来操作数值,以IEEE-754 64位格式存储,对数值进行位操作符的时候,会将64位转换成32位再进行位操作,最后将结果转换为64位,
所以对于开发者而言64位是透明,直接位操作32位的整数
⚠️NaN和Infinity会当作0来进行位操作
⚠️对于非数值会Number转换成数值
有符号整数:第32位是符号位,0正1负,正数是二进制,负数是绝对值的二进制补码(反码+1)
无符号整数:32位都表示数值,且只能是正数
按位非~:反码(25的反码是-26,-26的反码是25,其实就是操作值的反码-1得出的结果,但是位操作是在数值表示的最底层执行操作,速度更快)
按位与&:都是1才是1
按位或|:有1就是1
按位异或^:不一样才是1
左移<<:数值位左移,如果是有符号整数符号位不动,右侧的空位用0填充
有符号右移>>:保留符号位,空位用符号位数值填充
无符号右移>>>:以0填充空位,所以对于正数(无符号整数或者有符号整数是正数的情况)进行无符号右移和有符号右移结果一样,因为都是0填充,而负数(有符号整数是负数的情况)就有差别了,且负数进行无符号右移会让结果大大的变大了,因为填充用了0就变成了正数直接当作正数的二进制码而不是负数的补码二进制来识别啦
⚠️之前存在过理解错误,理解成有符号位移是针对有符号整数的操作,无符号位移是针对无符号整数的操作,而无符号操作会区别正数负数的情况,这和无符号整数都是正数相矛盾,其实这两个方法不是以有无符号整数维度划分的,是以动不动符号位的维度划分的,所以有符号右移是要依据符号位填充的,只操作有符号整数,而无符号右移不依据符号位填充(都填充0),所以可以操作有符号整数和无符号整数
布尔操作符
逻辑非!:转换成布尔值后再转非,转换规则就是Boolean的那种,双叹号模拟了Boolean方法
逻辑与&&:都对则对,短路操作(第一个能决定结果不会执行第二个求值)
逻辑或||:有对则对,短路操作,可以用逻辑或避免变量赋值null和undefined1
var myObject = preferredObject || backupObject;
乘性操作符
ECMAScript定义了3个乘性操作符,乘法(*)/除法(/)/求模(%)
非数值类型参与乘性操作符都会先调用Number()方法转换成数值类型后再计算
加性操作符
ECMAScript定义了2个加性操作符,加法(+)/减法(-)
加法规则:
1、️若操作数存在一个是字符串,另一个操作数要转换成字符串再拼接
2、️否则非数值会Number转换成数值来进行加法操作,⚠️⚠️⚠️对象类型依照上一节的Number规则(第一张图中描述的对象先调用toString是错误的),更正图见第二张…
部分实践结果如下:




减法规则:
1、一个操作数是非数值,会主动调用Number()转换成数值后再做减法运算
2、否则两个操作数都是数值就直接做减法

关系操作符
>/>=/</<=,结果返回布尔值
规则:
1、当两个操作符都是字符串时按照顺序依次比较两个字符串的字符编码(大写字母的编码比小写字母编码小)
2、否则非数值操作数要转换成数值再进行比较,若有操作符不能转换成数值也就是转换成NaN了,那怎么比较都是false

⚠️上图中标红的根据实际情况不太合理
第一种’Black’应该大于’apple’,但是B字母大写的编码比小写的小,解决可以是调用toLowerCase()统一小写后再比较
第二种是’23’应该大于’3’,但是首个字符串单元’3’字符编码小于’2’的字符编码,所以不要都是字符串进行比较,应该转换成数值再比较

相等操作符
相等和不相等 => 先转换再比较(强制转型)
全等和不全等 => 仅比较而不转换
==和!=
转型规则:
1、操作数存在数值都要转换成数值,再比较
2、布尔值会主动被转换成数值,再比较
3、null和undefined在比较前不会转换成其他类型,且null == undefined
4、NaN和任何值都不等,包括自己本身
5、仅有一个对象则调用Number(),再比较
6、两个都是对象则比较两个对象是否指向同一个对象,是true,否false


===和!==
在比较之前不转换任何操作数,除此之外没有什么不同
相比推荐使用全等和不全等
条件操作符
a>b ? a : b
赋值操作符
=
复合赋值操作+=、-=、*=、/=、%=、<<=、>>=、>>>=
逗号操作符
1、声明多个变量1
var a = 1,b = 2;
2、赋值1
2var num = (1,2,3,4,5)
// num的值是5
语句(流控制语句)
if语句
表达式返回值不是布尔值时自动调用Blooean()方法
1 | if(){ |
do-while语句
后测试语句,循环体至少会被执行一次
1 | do{ |
while语句
前测试语句,循环体可能一次都不会执行1
2
3while(expression){
//do something
}
之前面试时有道题是随机生成10个1-100之间不重复的数值,从中取得最高值和最低值,当时还被懵住了尴尬,while和for都行
for语句
前测试语句,循环体可能一次都不会执行,相比while语句具有初始化变量和定义循环后要执行的代码的能力
⚠️使用while做不到的for也做不到
1 | for(var i=0; i<10; i++){ |
⚠️初始化表达式,控制表达式,循环后表达式都是可选的1
2
3
4// 无限循环
for(;;){
//do something
}
for-in表达式
精准的迭代语句,枚举对象属性,若要枚举的对象是null或undefined,循环体不执行
⚠️返回属性顺序因浏览器而异
1 | // var非必须,为了保证局部变量,建议用 |
label语句
在代码中添加标签以便将来由break或continue语句引用,加标签的语句一般要与for语句等循环语句搭配使用
1 | // label:statement |
break和continue语句
break => 退出循环,执行循环后面的语句continue => 退出循环,从循环体顶部继续执行(即执行下一个循环)
两者与label联合使用,返回代码特定位置,多发生在循环嵌套的情况下
1 | outermost: |
⚠️使用过度不易调试,建议用描述性的标签,且不要嵌套过多循环
with语句
将代码作用域设置到特定的对象中,目的是简化多次编写同一个对象
⚠️首先查找局部变量,没有再查制定的对象中是否有同名属性
⚠️严格模式下报错!!!
1 | with(location){ |
大量使用会导致性能降低,不易调试,不推荐用
switch语句
目的是避免写很长的if-else语句
1 | switch(expression){ |
⚠️switch里可是是任何类型数据
⚠️case可以是常量/变量/表达式
⚠️比较用的全等操作符
函数
返回值相关:
函数可以没有return返回值,当不return时,其实返回了undefined
函数可以在任何时候return,当return后面没有跟具体值时会返回undefinedreturn后面的语句不会执行
推荐一个函数要么始终有一个返回值,要么就没有返回值,便于调试
严格模式限制:(以下会导致语法错误无法执行)
不能把函数名字和参数名字命名为eval或者arguments
参数名不能相同
参数:
函数参数是以一个包含零或多个值的数组的形式传递,函数接受的始终是这个数组,并不关心数组中包含哪些参数,函数内通过arguments对象访问这个数组
平时写的函数中命名的参数只提供便利,不是必须的arguments不是Arrary的实例,类似数组,可以通过方括号语法arguments[0]读值arguments的值始终与命名参数的值保持同步,但内存空间是独立的,当改变arguments的值时会同步到命名参数中,前提是参数值有被传递进来,若没有传递进来,arguments取值是undifined,arguments长度由实际传递进来的参数个数决定,不由定义的决定

重载:
没有签名、没有重载
先后定义两个同名函数,后定义的函数会覆盖前一个函数
通过检查传入函数中参数的类型和数量做不同的响应,来模仿重载