最近在看ES6(可能是初到公司的缘故,处于振奋与繁忙的事带来的无力之中。。。不过还是坚持认真阅读了《深入浅出ES6》,真心觉得是本好书),里面一些内容会时不时让人有“恍然大悟”之感。
先说下 JS数据类型:
原始数据类型和引用数据类型
原始数据类型 (6种)
- boolean
- null
- undefined
- number
- string
- symbol
引用数据类型:
- 对象 object(包括object,Array,RegExp,Date,Math…)
- 函数 Function
这里的“null”是个对象吗?
我们 console.log(typeof null);
,会输出:object。但这只是JS存在已久的Bug,它不是对象。
但JS之初用的32位系统,为了性能考虑使用低位存储变量的类型信息,000开头代表是对象,然而null全0,所以,就将其判为object。
typeof能否正确判断类型?
我们知道,对于原始类型:除了null都可正确判断。
但对引用数据类型,除函数外,皆为object。
这样,采用typeof未免有些不合适。
我们想到了 instanceof——基于原型链的查询 。
var str='hello!';
str instanceof String // false
const Person=function(){}
const p1=new Person()
p1 instanceof Person // true
它当然也能判断基本数据类型:
class PrimitiveNum{
static [Symbol.hasInstance](x){
return typeof x==='number'
}
}
console.log(111 instanceof PrimitiveNum) // true
其实,我们就是通过Symbol将原有的instanceof重新定义成了typeof,这是自定义instanceof行为的一种方式。
玩个刺激的,
手动实现instanceof
我想到了 基于原型链的向上查找
function myInstanceof(left,right){
//基本数据类型直接返回false
if(typeof left !== 'object' || left === null) return false;
//利用Object的自带方法拿到参数的原型对象
let proto=Object.getPrototypeOf(left);
while(true){
if(proto==null) return false; //参数的原型可能为null
if(proto==right.prototype) return true;
proto=Object.getPrototypeOf(proto); //若上面不符,取自己的“原型对象”,继续向下走
}
}
测试一下:
console.log(myInstanceof("111",String)); // false
console.log(myInstanceof(new String("111"),String)); // true
有趣的是,《深入浅出ES6》也对此有一个示例:(ES5模拟默认参数,通过typeof检查参数类型)
function makeRequest(url,timeout,callback){
timeout=(typeof timeout !== "undefined") ? timeout : 2000;
callback=(typeof callback !== "undefined") ? callback : function(){};
//其余实现
}
运用:instanceof左操作数是一个类,右操作数是标识对象的类,如果左侧对象是右侧类的实例,则返回true
所以,一般用typeof判断基本类型,其余的再用instanceof判断
Object.is和===
作为 ES6的新增方法 ,Object.is() 和 Object.assign() 在ES里掀起了“简洁便利之风”。
我们着重说下Object.is()方法:
《深入浅出ES6》中提到:当你想在JavaScript中比较两个值时,可能习惯于使用相等运算符(= = )或全等运算符( = = =),许多开发者更喜欢后者,从而避免在比较时触发强制类型转换的行为。
但是,全等运算符也不一定准确啊:
+0和-0在JavaScript引擎中被表示为两个完全不同的实体,而全等运算符却将其归为一类;
NaN===NaN的返回值应该为true,但在JavaScript中也需要使用isNaN()来表示。
ES6引入了Object.is()方法来弥补全等运算符的不准确运算:
console.log(+0 == -0); // true
console.log(+0 === -0); // false
console.log(Object.is(+0,-0)); // false
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN,NaN)); // true
console.log(5 == "5"); // true
console.log(5 === "5"); // false
console.log(Object.is(5,"5")); // false