类型
javaScript中的类型和熟知的一些强类型语言的有关类型的定义是不一样的。在js中,类型的含义是值的内部特征,它定义了值得行为,以使其区别于其他值。(a type is an intrinsic, built-in set of characteristics that uniquely identifies the behavior of a particular value and distinguishes it from other values)。
由此我们就可以看出,js强调的是值的行为,js认为拥有不同行为的值就是不同类型的值,而根据不同行为进行分类,js区分了七种类型:Undefined、Null、Boolean、Number、Object以及ES6新增的Symbol。
一:null和object
typeof null === 'object'; // true
typeof {} === 'object'; // true
在js中,null被当做object,这是js的一个BUG,修复这个BUG的代价有些大,所以相当时间内不会有什么变化,所以为了准确区分null和object,可以借助取反运算符,如下所示:
!null === true; // true
!{} === false; // true
var a = null;
if (!a && typeof a === 'object') { // 为true时,a为null
...
}
如上所示,借助这个区别,我们就可以准确区分null和object了。
二:typeof function a() {} === 'function'
如标题所示的结果为true。'function'是object的一个“子类型”。函数是“可调用对象”,它有一个内部属性[[Call]],该属性使其可以被调用。
typeof [1,2,3] === 'object'; // true
同理,数组也是对象,也是object的一个“子类型”。
三:JS中的变量没有类型,值有类型
JS中的变量并不具有类型,所以变量存储的值可以是任意类型且是动态可变的。所以我们说JS是一种“弱类型语言”。
所以,我们在使用typeof检查类型时,检查的并不是变量的类型,而是该变量存储的值的类型。因为JS中的变量没有类型。注意:typeof运算符的返回值总是一个字符串。
四:区分undefined和undeclared
- undefined:未赋值
- undeclared:未定义
在js中,undefined表示变量本身已经定义,但是还没有对该变量赋值或者被显示的赋值为undefined。如下所示:
var a;
typeof a; // 'undefined'
var c = 2;
typeof c; // 'number'
c = a;
typeof c; // 'undefined'
与undefined形成鲜明对比的,就是undeclared。如果我们完全还没声明,就直接去调用(注意,这里是直接调用未声明的变量),就会报错,如下所示:
var a;
a; // 'undefined'
c; // 'Uncaught ReferenceError: c is not defined'
"c is not defined"并非字面意思表示未定义,这也是为什么要引入一个"undeclared",因为在此处"c is not declared"更准确一些。
但需要注意的一点是,不论是对于已经定义未赋值的变量,还是对于未定义的变量,typeof操作符都会返回"undefined"。
var a;
typeof a; // undefined
typeof c; // undefined
会出现上述这种奇怪的现象,是typeof有一个特殊的安全防范机制。这种安全机制还是比较有用的。我觉得大家都写过如下所示的这种代码,但我们需要使用一个变量时,为了避免一些不必要的操作,可能会先对该变量做一个判断:
var name = ''
if (name) { // 如果name的值是空字符串,就不输出
console.log(name);
}
if (age) { // 如果age的值是小于等于0的值,就不输出
console.log(age);
}
现在我们知道,如上所示的代码是存在安全隐患的,我们无法保证name和age都是已经声明过得变量,这就存在安全隐患。这就需要做一个安全验证,这时候typeof的安全机制就有了用处:
var name = '';
if (typeof name !== 'undefined' && name) { // 如果name的值是空字符串,就不输出
console.log(name);
}
if (typeof age !== 'undefined' && age) { // 如果obj.age的值是小于等于0的值,就不输出
console.log(age);
}
同时,typeof操作符还可以验证某个变量当前是否有定义,避免同名覆盖。
if (typeof a === 'undefined') {
a = {...};
}
当然,如果是访问对象的一个不存在的属性,是不会像访问未声明的变量那样报错的。
var obj = {
name : 'abc'
}
if (obj.name) { // obj.name => 'abc'
console.log(obj.name); // 'abc'
}
if (obj.age) { // obj.age => 'undefined'
console.log(obj.age);
}