/*===无关紧要的开头start===*/
作为一个年轻的前端从业者,近期趾高气昂的去各种面试,抱着找虐心态去单挑的结果就是被各种面试题晃断脚踝并被yan射,然后开始质问自己对js的掌握为何如此浅薄,为何当初不好好学世界上最好的语言php。
当然,这不仅提醒了我得背背面试题,还要时刻谨记,要写安全规范的javascript代码
然后小总结了一下那天面试上来的就被隔扣的第一题。
/*===无关紧要的开头end===*/
问题
null === undefined; // false
null == undefined; // true
null === 0; // false
null == 0; // false
false === 0; // false
false == 0; // true
true === 1; // false
true == 1; // true
true == '1'; // true
true == 2; // false
undefined === 0; // false
undefined == 0; // false
NaN === NaN; // false
NaN == NaN; // false
!NaN == !NaN; // false
!NaN; // true
null == NaN; // false
!null == !NaN; // true
!null === !NaN; // true
if(!NaN) console.log('妈呀,这都是啥啊'); // '妈呀,这都是啥啊'
false || 0; // 0
!(false || 0) // true
true && 1; // 1
true && 2; // 2
!(true && 2) // false
!(false || 2) // false
let a = 123;
let b = new Number(123);
a === b; // false
a == b; // true
let a = document.getElementsByTagName('a');
let b = document.getElementsByTagName('a');
a === b; //true
let c = document.querySelectorAll('a');
let d = document.querySelectorAll('a');
c === d; //false
/*待续。。。*/
解答
答案在问题里边,真是皮得很...
其实这些是我根据当时的面试题整理和扩充的,有些代码中真的是碰不上,但是顺手都写上了。其实有些经验的开发者都会知道这些,小的不才在这再说那么一小下。
还有一些ES6中的set和map和symbol等后期会写到另一篇上。
正经解答
这道题中涉及到强等、弱等、js中基础类型转换、悬疑NaN、null和undefined、选择器等
js中的弱类型造福了人类,到处都是它贴心的帮你各种转换,让我们的代码在浏览器上、在webview上、在node里、在各种模拟器里、在喜马拉雅山上、在尼斯湖里、在握不紧的指尖上、在人生的光辉岁月里跑的流畅且难以预料。
所以:如何安全的写js,其实真的很重要(忘了这是谁说的了)。
以下只是我的一些理解,欢迎指正?
1. === 和 == 和类型转换
虽然看了一个很棒的总结(https://www.cnblogs.com/nelso...)
但是自己的想法还是要讲:
‘===’:
(1) 如果是基础类型进行比较,第一件事儿就是比较一下两边的数据类型,如果不一样,直接false
(2) 如果两个数据类型(这里指的还是基础类型)一样,那接下来就是直接的“值”的比较了
(3) 如果是引用类型的变量或者是内置函数构造出的变量进行比较,那么就是指针的比较了
(4) null和undefined,再强等面前,只和自己相等。
‘==’:
(1) 如果是基础类型进行比较,类型一样没得说,类型不一样,第一件事就是转一下,字符串转数字再进行值的比较,boolean类型转为数字
这里稍微总结了一下,可以顽固的认为 == 都是再比较数字,所有的都转换为数字,然后进行“值”的比较了(不知道接下来这么理解是好还是坏)
举个例子:'123' == 123 // true
其实就是 new Number('123') == 123,两边值一样,那就是true,不一样就是false;
再举个例子:
true == 1; //true
true == '1' // true
true == 2; // false
false == 0 // true
false == -1 // false
拿true == '1'来说
这样就是 new Number(true) == new Number('1')
其实还是两个为1的‘值’去比较
(new Number(true)返回一个 Number {1},new Number(false)返回一个 Number {0})
(2)如果是引用类型的变量或者是内置函数构造出的变量 和 基础数据类型 去比较,那就是这些变量的值拿出来去比较,例如 '123asd' == new String('123ads') 返回true
(3)如果是引用类型的变量或者是内置函数构造出的变量 相互比较,那还是指针的比较
2. NaN
NaN,感觉其实就是一个为了避免非数字的数字操作引起程序报错而设计的一个表示‘Not a Number’的存在,网上有好多好多介绍它的文字
NaN等于谁
因为讨论的强等和弱等,那在这只说一点:NaN和谁都不等,不管什么等
所以
———— NaN === NaN 是false
———— NaN==NaN也是false
———— new Number(NaN) == new Number(NaN)也是 false
很难理解为什么是这样,觉得是一个bug,其实我自己感觉这样是对的,因为它就是‘单纯的表示’这不是一个数字,并没有说是什么,such as:
NaN + 1; // NaN 那么一个数加一还是自己,那自己本来就不应该等于自己。。。
let a = 12/0 //a是NaN
let b = 13/0 //b是NaN,但是很简单看出a本来就不应该等于b(虽然再高数上它们是相等的)
let raptors = 81/'Kobe' //raptors也是NaN,raptors本来就不该等于a或者b
所以任何和NaN去比较的话,那都是“不等”!
NaN的判断
那么,该如何判断是不是NaN呢
不卖关子了,我就是来说 isNaN 和 Number.isNaN
大家都知道isNaN======>
isNaN不是看上去那个意思,不是判断“是一个NaN”,而是判断“不是一个数字类型的值”,isNaN看上去就是帮你在内部把传入的值进行了一次 new Number(param)的操作,然后new Number(param)返回NaN那就判断为true,但是字符串等类型就没有办法判断,如下:
isNaN(NaN); // 是个true
isNaN(NaN+1); // 当然还是个true
isNaN(123); //当然false
isNaN('123'); // 帮你转了个类型,就是内部执行了一下isNaN(new Number('123')),所以还是false
isNaN('Curry'); //返回true,内部执行了一下(new Number('Curry')返回了NaN
第五行的字符串,竟然被判定为NaN,实际上它的确不是一个数字,但是它的的确确不是我们需要判断的是一个NaN,所以这个方法只是用来判断“不是一个数字类型的值”
然后大家还知道Number.isNaN======>
es6来补漏了,Number.isNaN的出现解决了大家希望判断“是一个NaN”的操作。如下
Number.isNaN('Curry'); //返回false
NaN结束了
3. getElement* 和 querySelector*
在问题中有这样一个东西:
let a = document.getElementsByTagName('a');
let b = document.getElementsByTagName('a');
a === b; // true
let c = document.querySelectorAll('a');
let d = document.querySelectorAll('a');
c === d; //false
这衍生出来的:getElementsByTagName查出来是什么?querySelectorAll查出来的又是什么?
MDN上告诉我们:
———— getElementsByTagName查出来的是HTMLCollection,HTMLCollection是一个动态的dom节点集合,绑定在document的live上,随着document变化随时更新,指向每一个符合选择要求的dom节点,这既是为什么上边例子中 a===b 为 true 的原因了
———— querySelectorAll查出来的是NodeList,是一个单纯的选择器选出的dom节点集合,这就是为什么上边例子中 c===d 为 false 了
HTMLCollection和NodeList都是只读的。jQuery也是使用的querySelectorAll,所以jQuery选择器选择出来也是对NodeList进行操作,所以:
var a = $('a');
var b = $('a');
a === b; // false
所以,事件委托真伟大...
总结
其实由NaN、选择器、===和==、基本数据类型转换、内置函数构造出的对象结合进数组中,去判断数组值相等,去去重、去求交并补等操作,并结合set和map,都有很多讨论的话题,希望下次能分享给大家
感谢各位的阅读,这些只是我自己的一些理解和想法,希望不正确的地方各位能够帮忙指正。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。