使用constructor判断的时候要注意,如果原型上的constructor被修改了,这种检测可能就失效了,比如:
function a() {} a.prototype = { x: 1 } let b = new a(); b.constructor === a; // 注意这时候是 false上面为false的原因是,constructor这个属性其实是挂在a.prototype下面的,我们在给a.prototype赋值的时候其实覆盖了之前的整个prototype,也覆盖了a.prototype.constructor,这时候他其实压根就没有这个属性,如果我们非要访问这个属性,只能去原型链上找,这时候会找到Object:
要避免这个问题,我们在给原型添加属性时,最好不要整个覆盖,而是只添加我们需要的属性,上面的改为:
a.prototype.x = 1;如果一定要整个覆盖,记得把constructor加回来:
a.prototype = { constructor: a, x: 1 } duck-typingduck-typing翻译叫“鸭子类型”,名字比较奇怪,意思是指一个动物,如果看起来像鸭子,走起路来像鸭子,叫起来也像鸭子,那我们就认为他是只鸭子。就是说我们通过他的外观和行为来判断他是不是鸭子,而不是准确的去检测他的基因是不是鸭子。这种方式在科学上当然是不严谨的,但是在部分场景下却是有效的。用编程语言来说,就是看某个对象是不是具有某些特定的属性和方法,来确定他是不是我们要的对象。比如有些开源库判断一个对象是不是数组会有下面的写法:
function isArray(object) { return object !== null && typeof object === 'object' && 'splice' in object && 'join' in object } isArray([]); // true这就是通过检测目标对象是不是包含Array应该有的方法来判断他是不是一个Array。这就是所谓的看着像鸭子,那就是鸭子。但是一个具有splice和join方法的对象也能通过这个检测,所以这样是不准确的,只是部分场景适用。
Object.prototype.toString.callObject.prototype.toString.call是比较准确的,可以用来判断原生对象具体是哪个类型:
Object.prototype.toString.call(new Array()); // [object Array] Object.prototype.toString.call(new Date()); // [object Date]这个方法返回的是[object XXX],这个XXX是对应的构造函数名字。但是他只能检测原生对象,对于自定义类型是没有用的:
function a() {} let b = new a(); Object.prototype.toString.call(b); // [object Object]可以看到对于自定义类a的实例b,我们得到仍然是[object Object],而不是我们预期的[object a]。
一些原生方法: Array.isArray,Number.isIntegerJS为了解决类型检测的问题,也引入了一些原生方法来提供支持,比如Array.isArray和Number.isInteger等。Array.isArray可以用来检测一个对象是不是数组:
Array.isArray([]); // true Array.isArray(123); // falseNumber.isInteger可以用来检测一个对象是不是整数:
Number.isInteger(1); // true Number.isInteger(-1); // true Number.isInteger(-1.1); // false Number.isInteger('aaa'); // false如果有原生检测的方法我们当然推荐使用原生方法了,但是目前原生方法并没有那么多和全面,很多时候还是要用前面的方法来检测类型。
小节JS其实没有一种完美的方法来检测所有的类型,具体的检测方法需要我们根据实际情况来进行选择和取舍。下面是几种方法的总结:
总结JS有两种数据类型,原始类型和引用类型,引用类型主要就是对象。
当我们使用+,逻辑判断或者==时会有隐式的类型转换。
有时候隐式的类型转换会出现我们不想要的结果,如果我们确定要进行判断或者类型转换,最好使用显式的,比如使用===,而不是==。
对象转为字符串和数值可能需要调valueOf和toString方法,调用顺序需要看具体场景。
JS没有一个完美的类型检测方法,我们最好根据需要选择具体的检测方法。
文章的最后,感谢你花费宝贵的时间阅读本文,如果本文给了你一点点帮助或者启发,请不要吝啬你的赞和GitHub小星星,你的支持是作者持续创作的动力。