类数组对象和对象
文章开始先来看一下js中数组对象和类数组对象。在js中数组是一个对象,数组对象继承自Array对象
var arr1 = [];
var arr2 = new Array();
这两种方式定义出来的数组,由于Array.prototype上有大量的方法,因此数组对象可以使用多种方法。那么既然数组是一个对象,那么我们自然会想到用一个普通的对象来模拟数组对象,于是就出现了类数组对象
var likeArray = {
0: 'zero',
1: 'one',
2: 'two',
length: 3,
otherMethod: function(){
alert('otherMethod!');
}
}
这样构造出来的对象,使用数字字符串作为key值,还有一个length属性来记录对象中元素个数,也可以挂载其他方法,这样的对象就叫做类数组对象。类数组对象既可以用数字进行索引,也可以用for循环进行遍历,还有可以使用call转化成数组对象,这里不明白的可以参考我另外一篇文章call和apply上手分析
那么js有几种基本类型,String,Number , 布尔类型,Null,undefined。其中String类型同时也是类数组对象,类数组对象我们更关注它的使用,而不关心它的类型。
typeof和instanceof
接下来进入我们的主题,先看typeof的语法
typeof operand
typeof将返回operand的类型
typeof 0 // return 'number'
typeof '0' //return 'string',字符串同时也是一个类数组对象
typeof false // return 'boolean'
function fn(){ }
typeof fn // return 'function'
var param;
typeof param // return 'undefined'
//ES6 新加入的类型
typeof Symbol() // 'symbol'
typeof在判断基本类型的时候非常给力,但在判断对象时就力不从心,上文说到数组是一个有很多方法的强大对象,那么
typeof [1, 2, 3] // return 'object'
typeof null // return 'object'
typeof {x: 1} // return 'object'
typeof不能区分出数组,null和普通对象,那么instanceof解决了这个问题,下面看instanceof
A instanceof B
instanceof用来检查A的原型链上是否存在B的原型,或者直接一点说,B在不在A的原型链上,关于原型链继承可以参考我的另一篇文章原型继承及其应用
function A(){ }
function B(){ }
var a = new A();
a instanceof A(); // return true
a instanceof B(); // return false;
function Parent(){ }
function Child(){ }
Child.prototype = new Parent();
var grandChild = new Child();
grandChild instanceof Parent //return true
可以看到,只要B存在于A的原型链上就返回true, 那么
[1, 2, 3] instanceof Array //return true
null instanceof Object // return false
var obj = {}
obj instanceof Object // return true
这样就可以区分数组,null和普通对象,然而在一些基本类型的判断上
5 instanceof Number // return false
var num = new Number('5')
num instanceof Number // return true
'' instanceof String // return false
只有通过new出来的基本类型才能通过instanceof判断,所以,在判断是否字符串,是否数字,是否布尔值的时候,我们应该使用typeof。而对数组和要判断对象是否是在某个构造函数或对象的原型链上时使用instanceof,对函数的判断两者皆可。
我们还可以证明字符串是一个类数组对象
var a = '';
var str = new String('test');
str instanceof Object //return true
str instanceof String // return true
a instanceof String // return false
a instanceof Object // return false
通过构造函数new出来的字符串通过了检测,虽然字面直接量a没有,但是使用中推荐直接使用字面直接量。
if判断
再聊一聊if判断
var a = ...
if(a){
//do something
}
实际上就是
var a = ...
if(typeof a !== 'undefined' && a !== 0 && a !== null && a !== false){
// do something
}
我们注意到,对这四个值typeof,只有null会返回 object
。所以当我们想判断一个对象是否为null的时候,需要用复合条件
if(!obj && typeof obj === 'object')
当我们想判断一个对象是否是null或undefined的时候,可以使用
// 只有null和undefined会返回true
if(obj == null)
当我们在if判断中使用未定义的变量时,就会报错。
if(b){ ... } // b is not defined...
在调试模式中,DEBUG变量的声明只有在开发和测试时才会被加载到浏览器,在生产环境中不予加载,这时我们要怎么检测DEBUG变量是否声明呢,安全的方法是使用typeof
if(typeof DEBUG !== 'undefined'){
console.log('debug is beginning')
}
当if判断中的变量是某个对象的属性时
var obj = {
data: {
num: 5
}
}
//不推荐
if(obj.data.num){
obj.data.num ...
}
//推荐
var a = obj.data.num;
if(a){
...
}
在取对象属性层级嵌套的时候,先保存在变量中,既可以避免重复取属性消耗性能,又可以避免出错,在使用if判断以及typeof和instanceof的时候,要注意这一点