记录个人学习过程中觉得有意思的一些知识点。当然对于大神们来说只是基础知识啦。
1、..toString是什么语法?
3.toString()
3..toString()
3...toString()
分别返回什么?
第一反应
3.toString() // "3"
3..toString() // 这是什么语法?
3...toString() // 这又是什么语法?
实际结果是
3.toString() // Uncaught SyntaxError: Invalid or unexpected token
3..toString() // "3"
3...toString() // Uncaught SyntaxError: Unexpected token .
这是因为,在js中,3.
是一个合法的number,所以在执行的时候,3.
会被识别成一个number,以上代码可以翻译成
let number = 3.;
numbertoString();
number.toString();
number..toString();
这样结果就一目了然了。
2、NaN什么情况下等于NaN?
NaN
,即非数值(Not a Number)是一个特殊的数值,它与任何值都不相等,包括NaN
本身。不管是执行NaN == NaN
还是NaN === NaN
都会返回false
。
那么NaN
在什么情况下会等于NaN
呢?见证奇迹的时刻,
let set = new Set();
let a = NaN;
let b = NaN;
set.add(a);
set.add(b);
set // Set {NaN}
我们利用Set
不会添加重复的值得特性,往里面添加了两个NaN
,结果第二个NaN
被认为重复数字被去重了。可见,在Set
里,NaN
是相等的。
3、typeof并不是一个100%安全的语法
typeof
是我们常用的一个方法。用于检测变量类型。如
typeof "1"; // "string"
typeof 1; // "number"
typeof true; // "boolean"
typeof function() {}; //"function"
甚至
typeof Infinity; // "number"
typeof NaN; // "number"
typeof undefined; // "undefined"
typeof null; // "object"
typeof 1n; // "bingint" 这是另一个知识点
但是有时候自从ES6后,胡乱使用也会翻车。如下:
typeof x; // "undefined"
var x;
typeof y; // ReferenceError
let y;
4、a==1 && a==2 && a==3
如何让上例等式成立?
用到的知识点是js中的隐式转换。如果一个操作数是对象,则调用对象的valueOf()
方法,用得到的基本类型值按照前面的规则进行比较;所以我们重写valueOf
就好了。
var a = {
i: 1,
valueOf() {
return a.i++;
}
}
if( a == 1 && a == 2 && a == 3 ) {
console.log(1);
}
5、01 + 0.2 = ?
在数学的领域里,毫无悬念,0.1+0.2=0.3
。但是在JavaScript中,运行
0.1 + 0.2 === 0.3 // false
结果却是false
。简单说明一下
JavaScript使用Number
类型表示数字,包括整数和浮点数,遵循 IEEE 754标准。
将两数分别转换为二进制:
0.1 -> 0.0001100110011001...(无限循环)
0.2 -> 0.0011001100110011...(无限循环)
根据双精度浮点数的定义,Number
类型中有效的整数范围是-0x1fffffffffffff
至0x1fffffffffffff
,所以Number
无法精确表示此范围外的整数。
那么这里有两个问题:
- 既然
0.1
是转换成二进制是无限循环小数,那么为什么我们使用0.1
的时候,0.1
就是0.1
并没有出现精度丢失的问题?- 那我们如果进行
0.1+0.2=0.3
的比较呢?
首先第一个问题,0.1
之所以等于0.1
,因为0.1
失去精度后等于0.10000000000000000555
,而js的数字精度为2**53
,长度为16
位。0.10000000000000000555.toPrecision(16)
刚好位0.1
。
第二个问题,可以用JavaScript提供的最小精度值来判断
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
6、"+"不仅仅是加号
上面说到了+
,联想到另一个有意思的知识点。+
符号是我们经常使用到的符号,可以用来对Number
进行求和,有String
则进行拼接。如果是对象,就valueOf
之后再拼接(valueOf
没有值则调用toString
),如
1 + 1; // 2
"1" + "1"; // "11"
"1" + {toString(){return 1}}; // "11"
顺便记录一下平时很少用到的特殊值。
(+0) + (-0); // +0
(-0) + (-0); // -0
Infinity + (-Infinity); // NaN
NaN + 任意的Number类型; // NaN
1 + undefined; // NaN
"1" + undefined; // "1undefined"
回到正题,提问
[] + {}; // ?
{} + []; // ?
按照刚刚总结的知识,对象相加,由于valueOf
是其本身,所以是拼接的其toString()
值。所以上例等价于
[].toString() + {}.toString(); // "" + "[object Object]" => "[object Object]"
{}.toString() + [].toString(); // "[object Object]" + "" => "[object Object]"
所以结果应该是一样的?讲道理似乎没毛病,但有意思的地方在于{}+[]
的结果并非是我们的预期值,而是0
。
这是由于浏览器会将{}+[]
前面的{}
识别为语句块,所以{} + []
等价于+[]
,此时+
并不是加号,而是一元加操作符。
一元加操作符
以一个加号(+)表示,放在数值前面,对数值不会产生任何影响。不过,在对非数值应用一元加操作符时,该操作符会像Number()
转型函数一样对这个值执行转换。换句话说,布尔值false
和true
将被转换为0
和1
,字符串值会被按照一组特殊的规则进行解析,而对象是先调用它们的valueOf()
和(或)toString()
方法,再转换得到的值。
所以+[]
的计算过程分解如下
+[] => Number([].toString()) => Number("") => 0
所以以下式子也不难理解了
[] + []; // ""
[] + {}; // "[object Object]"
{} + []; // 0
{} + {}; // 这个结果会根据浏览器不同而产生不同的结果,Chrome上结果为[object Object][object Object],为直接字符串相拼,Firefox上为NaN,因为将前一个{}识别成代码块,所以+{} => Number({}.toString()) => Number("[object Object]") => NaN
7、border-radius的另类用法
看了上文密密麻麻的文字之后来画画图。将如下css
画出来:
{
width: 200px;
height: 100px;
background: red;
border-radius: 200px/100px;
}
前三条很简单,宽200,高100,红色背景。知识点在最后一条上,border-radius: 200px/100px
。我们很少这样去给一个盒子设置边框。但是我们可以猜测一下可能的形状。
200px/100px
,圆角弧度是2
?2px
?200%
?
首先,2
肯定是不对的,没有单位是个什么鬼?2px
从表达式上倒是没问题,但可惜并不是正确答案。200%
呢?恭喜,如果你认为是200%
,那么你可以画出正确的图形。
因为当border-radius
的值超过50%
后,实际上形状是不会再发生变化了。但遗憾的是,虽然画出了正确的图形,却不是正确的解答。
实际上,在Chrome上测试可知
border-radius: 200px/100px
其实等价于
border-top-left-radius: 200px 100px;
border-top-right-radius: 200px 100px;
border-bottom-left-radius: 200px 100px;
border-bottom-right-radius: 200px 100px;
每一个角的圆角弧度都是200px 100px
,真实的形状应该是这个样子
拓展一下,如果把上例样式改成
{
width: 200px;
height: 100px;
background: red;
border-radius: 200px 100px;
}
又会是什么样子?不知道的话动手试试吧。
不定期更新