Number
- 使用八进制和十六进制格式创建的数值在所有数学操作中都被视为十进制数值。
- 正零和负零在所有情况下都被认为是等同的
- ES6 中的八进制值通过前缀
0o
来表示 - 科学计数法
- ECMAScript 不区分整数和浮点值,只有 Number 一种数值数据类型。
常用方法
Math.ceil()
:取最高整数(天花板)Math.floor()
:取最低整数(地板)Math.round()
:四舍五入- 原理:对传入的参数+0.5之后,再调用
Math.floor()
- 原理:对传入的参数+0.5之后,再调用
Math.random()
:生成 [0,1) 的随机数(64位双精度浮点数)toFixed()
:参数为小数位数,限制小数位数,四舍五入,返回字符串toExponential()
:参数为小数位数,返回科学记数法字符串toPrecision()
:会根据情况返回最合理的输出结果,使用以上两种之一Number.isSafeInteger()
:参数是否在安全范围内Number.isInteger()
:参数是否为整数
精度问题
-
精度
-
js的数字都是以64位双精度浮点数形式储存的
-
当需要整数时,会自动浮点数,转成整数
-
js的精度范围:[-253,253]
-
-
精度丢失
-
数值超过范围会丢失,但主要还是小数造成的
-
在小数(十进制)转为二进制存储的过程中,以
2
的整数次幂作为除数时,不会有精度丢失(比如1/2、1/4、1/8等等) -
但其他情况下,会被转为无限循环小数,从而失去精度(比如1/10、1/11等等)
-
-
解决精度丢失:
- 将小数转化为整数计算避免小数存储问题
- 转化为字符串进行处理
- bigInt(只能处理整数精度问题)
Infinity
- 超出范围会转为Infinity
Infinity / Infinity
,返回 NaNInfinity - Infinity
,返回 NaNInfinity - -Infinity
,返回 NaNInfinity * 0
,返回 NaNInfinity % 有限值
,返回NaNnull / Infinity
,返回 0Infinity / null
,返回 InfinityInfinity * null
,返回 NaNInfinity
与undefined
计算,返回的都是NaN
。
NaN
- 与任何数(包括自己)进行运算,结果都为NaN
- 0 除以 0,返回 NaN
NaN!=NaN
,返回true
识别NaN | 不识别NaN |
---|---|
includes() | === |
Set、Map | == |
Object.is(NaN,NaN) | indexOf |
isNaN(NaN) |
数值转换
Number()
Number() | 结果 |
---|---|
null | 0 |
undefined | NaN |
数值 | 直接返回 |
布尔值 | 1 | 0 |
对象 | valueOf() => toString() |
字符串 | 忽略无意义的空格和0;转为十进制;其他转为NaN |
空字符串 | 0 |
一元加操作符与 Number() 函数遵循相同的转换规则
parseInt
- 忽略无意义的空格和0
- 如果第一个字符不是数值字符、加号或减号,返回 NaN
- 所以空字符串会返回NaN
- 否则会一直解析到非整数数字结束(小数点会不符合)
- 识别各种进制
- 也可以通过参数二传入要转换的进制数(此时,0x或者0可以忽略)
parseFloat
- 忽略所有开头的0和无意义的空格
- 只解析十进制值(因为忽略所有开头的0)
- 如果第一个字符不是数值字符、加号或减号,返回 NaN
- 所以空字符串会返回NaN
- 否则会一直解析到非浮点数数字结束
- 尽可能表示为整数
Number.prototype.toString()
- 有参数:进制转换
- 无参数:转为字符串
运算符
数据类型处理
- 原始类型转为数值,一般调用Number()
- 原始类型转为字符串,一般调用toString(),只有undefined 和 null ,调用String()
- 对象转为原始类型,一般会调用 valueOf() => toString() ,只有 Date 是 toString => valueOf
运算符
- 一元运算符:只操作一个值
- 前缀与后缀
- 加号和减号
- 二元运算符:
- 只限加法:有一个是字符串,则另一个也要转为字符串(字符串拼接功能)
- 如果不想转为字符串,则用圆括号
()
(括号优先级高)
- 如果不想转为字符串,则用圆括号
- 有一个是字符串,转为数值
- 对象转为原始类型
- 除法
/
:0 / 0
,返回NaN有限数 / 0
,返回Infinity 或 -Infinity
- 求模
%
:有限值 % 0
,返回NaN0 % 0
,返回0
- 只限加法:有一个是字符串,则另一个也要转为字符串(字符串拼接功能)
- 布尔运算符:
- 逻辑非
!
:调用Boolean(),然后取反 - 逻辑或
||
和逻辑与&&
有短路的作用,值应该取决谁,就返回谁
- 逻辑非
- 比较运算符:
- 字符串比较,逐个比较字符编码
- 数值和字符串比较,字符串先转换为数值,再进行数值比较
- 在涉及比较 NaN 时一律返回 false
- 相等运算符:
- 对象是地址比较
- 原始类型与引用类型比较,引用类型转需要先转为原始类型
- 等于
==
与不等于!=
:先转换为数值再比较 - 全等
===
与全不等!==
:不进行转换
- 逗号运算符:可以一次执行多条语句
- if 语句:对判断结果自动调用Boolean()
- switch语句:使用全等进行匹配
- for…in:遍历对象的属性(不识别Symbol)
- for…of:遍历可迭代对象的属性(不识别Symbol)
在使用循环时,为了确保这个局部变量不被修改,推荐使用 const
-
可选链运算符:
?.
(详情见《Object》一章) -
Null 判断运算符:
??
-
null
,undefined
,空字符串
,false
,0
都会被判断为false,范围很大 -
??
只有运算符左侧的值为null
或undefined
时,才会返回右侧的值。 -
跟
?.
配合使用,为null
或undefined
的值设置默认值。obj?.a?.b?.c?.d??3 //3
-
这个运算符很适合判断函数参数是否赋值。
-
二进制
- 符号位:最高位作为符号位,0 表示整数, 1 表示负数,其余31位表示数值。
- 负数在计算机中以补码形式存储
- 负数的原码 = 符号位变为1(取绝对值)
- 负数的反码 = 在原码的基础上,符号位不变,其他位取反
- 负数的补码 = 反码 +1
- 正数的原码、反码、补码都一样
- 0的反码、补码都是0
位运算
-
在运算前会将64位转为32位整数进行运算,完事后再转为64位(取整)
-
NaN 和 Infinity在位运算中都会被当成 0 处理。
-
在使用位运算时,如果位非数值,会先调用Number()转为数值
-
位运算一律先转换为二进制进行计算
运算符
-
按位或:符号为
|
,二进制位一真则真 -
按位与:符号为
&
,二进制位一假则假 -
按位否:符号为
~
,二进制取反 (最快的取整,两次取反) -
异或运算符:符号为
^
,二进制位不同为真,相同为假 (最快交换两数值)var a = 10; var b = 99; a ^= b, b ^= a, a ^= b; a // 99 b // 10
-
有符号左移:符号为
<<
,二进制位左移 (乘法)-
向左移动指定的位数,尾部补
0
-
1 << 5
相当于1 × (25) = 32 -
1 << 0
相当于1 × (20) = 1
-
-
有符号右移:符号为
>>
,二进制位右移 (除法)-
右移动指定的位数,如果是正数,头部全部补
0
;如果是负数,头部全部补1
-
16 >> 3
相当于16 / (2^3) = 2
-
-
无符号右移:符号为
>>>
- 右移动指定的位数,不管符号位,全部补
0
- 右移动指定的位数,不管符号位,全部补
生成[min,max]
范围内随机整数
function _random(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
初步思路
-
范围问题:Math.random()默认范围为[0,1),先乘上(max-min),将范围扩大到[0,(max-min)),再加上min,整体范围就变成了**[min,max)**
-
整数问题:js为64位双精度浮点数,使用四舍五入可以将其变为整数,但其实Math.round的原理是Math.floor,所以我们使用Math.floor将其转为整数,而且Math.round会有概率问题
-
使用Math.floor,没有概率问题,但需要加1来扩大范围
-
1 to 1.9999999999 become 1(0.99)
-
2 to 2.9999999999 become 2(0.99)
-
3 to 3.9999999999 become 3(0.99)
-
优先级
- 多个new 从右往左
.
从左往右.
> new 函数 > 函数调用
function Foo() {
//未声明,被调用就会变成全局变量
getName = function () {
console.log(1);
}
return this
}
Foo.getName = function () {
console.log(2);
}
//原型对象 3
Foo.prototype.getName = function () {
console.log(3);
}
var getName = function () {
console.log(4);
}
function getNmae() {
console.log(5);
}
/*
GO{
getName:undefined ->function输出5 ->function输出4->function 输出1
Foo:function
Foo.getName:输出2
}
*/
Foo.getName(); //2
getName();//4
//执行后,改变全局变量
Foo().getName();//1
getName();//1
/*
. > new 函数()
先获取函数,再new
相当于分为两块
new (Foo.getName)() //2
*/
new Foo.getName(); //2
/*
先执行 . 发现左侧有函数调用和new,所以先执行new
所以可看作(new Foo()).getName()
new 后返回的this也会变成对象,继承原型对象
*/
new Foo().getName()//3
/*
. > new >调用
可以看作new ((new Foo()).getName())
*/
new new Foo().getName()/
面试
【1】
["1","2","3"].map(parseInt)//1,NaN,NaN
-
展开为
parseInt('1',0) //1 parseInt('2',1) //NaN parseInt('3',2) //NaN
【2】
[[3,2,1].reduce(Math.pow),[].reduce(Math.pow)]
//[9,Error]
//an error
-
展开为
Math.pow(3,2) Math.pow(9,1)
-
只有reduce数组为空会报错
【3】
var val = 'smtg';
console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing');
//Something
+
的优先级 大于?
【4】
var two = 0.2
var one = 0.1
var eight = 0.8
var six = 0.6
[two - one == one, eight - six == two]
//[ true, false ]
- 精度问题
【5】
function isOdd(num) {
return num % 2 == 1;
}
function isEven(num) {
return num % 2 == 0;
}
function isSane(num) {
return isEven(num) || isOdd(num);
}
var values = [7, 4, '13', -9, Infinity];
values.map(isSane);
//[true, true, true, false, false]
-
||
具有短路的特性,值应该取决谁,就返回谁 -
-9进哪个函数结果都是false
【6】
'5' + 3
'5' - 3
//'53', 2
- 只有
+
可能切换为拼接功能
【7】
3.toString()
3..toString()
3...toString()
//error, '3', error
.
在表示数字时优先级高于对象调用
【8】
var min = Math.min(), max = Math.max()
min < max
//false
- Math.min 不传参数返回
Infinity
, Math.max 不传参数返回-Infinity