js各种冷知识
1. isNaN()
与Number.isNaN()
在JavaScript中,NaN是一种特殊的值
NaN表示(not a number 不是一个数字),如果数学运算符的操作数不是数字类型,且无法隐式转换成数字类型,则会返回NaN.
常见的对NaN困惑有:
-
NaN的类型是number
typeof NaN ; //number
对,如你所见,“not a number”是一个number。旦旦是野蛮自学的程序员,所以刚开始学时对这个没什么感觉,但听朋友说他当初刚看到typeof NaN的输出结果的number的时候,三观被冲击了好一会。呵,凡人的意志(doge) -
NaN是一个非自反的值,即NaN与NaN不相等。
NaN == NaN; //false
NaN === NaN; //false
这就意味着我们无法使用相等和全等关系运算符来判断一个值是否为NaN。
对于第二点问题,js提供了一个内置方法来判断NaN,即isNaN()方法,但这个方法存在一点问题。
var a = 20 * "旦旦";
var b = "旦旦";
isNaN(a); //true
isNaN(b); //true
乍一看确实,b在转化为数字类型的时候返回的是NaN,但b和a不同,a是经过数学运算符运算后的返回值,当我们将a打印出来也是明明白白的NaN;而b没有经过数学运算符返回,它本质上还是个字符串,打印出来是明明白白的“旦旦”,typeof b; //string
类型也是明明白白的字符串。
故isNaN还是不够准确,所幸ES6提供了一个更准确的方法,即Number.isNaN()
Number.isNaN(a); //true
Number.isNaN(b); //false
很显然,Number.isNaN()更符合语义也更为准确
2. 数字字面量后的".
"优先识别为字面量的一部分,而非对象属性访问符
js有一个特别方便但也有点玄幻的机制,即封装对象包装:
var num = 12.345;
num.toFixed(1); //12.3
在这个例子中,num明明是数字,是基本数据类型,却用对象访问符直接调用了一个方法,这是js内部自动用Number原生函数对num进行了封装,并调用了在Number中的toFixed方法。
但是,并不是所有形式的数字都能这样直接调用方法,如:
12.toFiexd(2); //SyntaxError
这里的“.”并没有被识别成对象属性访问符,而是被识别成了小数点,故提示语法错误。但以下写法不会提示语法错误且能正常调用方法:
12.0.toFiexd(2); //"12.00"
12..toFiexd(2); //"12.00"
(12).toFiexd(2); //"12.00"
3.js中2的1024次方以上是infinity
JavaScript中有一个神奇的值,叫infinity。这个值通常是使用某个数除于0得到的:
var a = 1/0; //infinity
var b = -1/0; //-infinity
然而,当一个数值足够大,也是可以使运算结果溢出成infinity的:
Math.pow(2,1023) //8.98846567431158e+307
Math.pow(2,1024) //infinity
-Math.pow(2,1023) //-8.98846567431158e+307
-Math.pow(2,1024) //-infinity
4.让引擎自己封装对象,比你自己创建封装对象性能更好
如题,当我们要访问字符串,数字这些基本数据类型的length,或者直接在基本数据类型的数后用“.”属性访问符调用方法时,让引擎自己判断什么时候使用封装对象,性能更好。如:
var name1 = "旦旦";
name1.split("") //性能好
var name2 = new String("旦旦");
name2.split("") //性能差
5. 最小化语句数:有利于性能提升
完成多个操作的单个语句,比完成单个操作的多个语句性能好。下面列举几例:
-
一个声明操作符声明多个变量
//一个var声明多个变量,性能好
var name0 = "旦旦0" , name1 = "旦旦1" , name2 = "旦旦2" , name3 = "旦旦3";
//多个var声明单个变量,性能差
var name0 = "旦旦0" ;
var name1 = "旦旦1" ;
var name2 = "旦旦2" ;
var name3 = "旦旦3" ;
var name4 = "旦旦4" ;
-
插入迭代值
//迭代值放里面,性能好
var name = arr[i++];
//迭代值放第二句,性能差
var name = arr[i];
i++;
-
使用字面量创建数组或对象
这个应该是总所周知了吧?用new实例化Array和Object的性能,会比用字面量声明的性能差。
6.==
和===
的性能其实差不多
js的相等比较操作符有两种,分别是宽松相等和严格相等,即俗称的相等和全等。
在比较方式上,==
会在相等比较过程中进行强制类型转换,===
则不允许这种转换。表现出来则是==
只要值在转换后能够相等就返回true
,而===
不行要值相等,数据类型也要同意才能返回true
。
这就造成一些开发者的误解,认为===
的性能比==
差,因为===
要做的事情更多,它不仅要检查值,还要检查值的类型。实际上==
和===
都会检查操作数的类型,只是在操作数类型不同时他们的处理方式不同而已。
7.var obj = {};
并不是"真正意义上的创建空对象"
在我们普遍的声明对象的方法中,不管是用字面量方法还是用构造函数方法,都不能真正意义上的创建一个空对象,如下:
虽然这两个对象里面没有我们赋予的属性,但引擎自动给我们的对象赋予了一个__prooto__
属性,这个属性里面保存了一个地址,指向Object.prototype
。这显然不符合我们对”空对象“的想象。
ES5给我们提供了一个方法,可以在创建对象的同时控制__prooto__
属性:
这种方法创建的空对象,显然比常用的变量声明方法”更空“,这也使得我们在对这种“更空”的对象进行操作时(如遍历),会更节省性能。同时,这种方式也能防止对象受原型链污染的影响。
(未完待续,持续更新)