数据类型

  • 6种原始类型:
    • boolean
    • number
    • string
    • null
    • undefined
    • Symbol (ECMAScript 6 新定义)
  • 一种引用类型 Object
    • Array
    • Object
    • Function
    • Date
    • RegExp
    • Error
    • Arguments

我们通常用来检测数据类型的方法,分别是typeof,Object.prototype.toString,instanceof

typeof

var und=undefined;
var nul=null;
var boo=true;
var num=1;
var str='xys'
var obj=new Object();
var arr=[1,2,3];
var fun=function(){}
var date=new Date();
var reg = /a/g;
var err=new Error()
var arg;
(function getArg(){
    arg=arguments;
})();
var symbol1 = Symbol();

console.log(typeof und);  // undefined
console.log(typeof nul);  // object
console.log(typeof boo);  // boolean
console.log(typeof num);  // number
console.log(typeof str);  // string
console.log(typeof obj);  // object
console.log(typeof arr);  // object
console.log(typeof fun);  // function
console.log(typeof date);  // object
console.log(typeof reg);  // object
console.log(typeof err);  // object
console.log(typeof arg);  // object
console.log(typeof symbol1);  // symbol

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

可以看到,使用 typeof 方法来检测数据类型,基本类型大部分都能被准确检测并返回正确的字符串(除了 Null 类型,其返回 object 字符串),而引用类型大部分都不能够被准确检测(除了 Function 类型能够准确返回 function 字符串外,其它的都返回了 object 字符串)

Object.prototype.toString

Object.prototype.toString 最终会返回形式如 [object,class] 的字符串,class 指代的是其检测出的数据类型,这个是我们判断数据类型的关键

var toString=Object.prototype.toString;

console.log(toString.call(und));  // [object Undefined]
console.log(toString.call(nul));  // [object Null]
console.log(toString.call(boo));  // [object Boolean]
console.log(toString.call(num));  // [object Number]
console.log(toString.call(str));  // [object String]
console.log(toString.call(obj));  // [object Object]
console.log(toString.call(arr));  // [object Array]
console.log(toString.call(fun));  // [object Function]
console.log(toString.call(date));  // [object Date]
console.log(toString.call(reg));  // [object RegExp]
console.log(toString.call(err));  // [object Error]
console.log(toString.call(arg));  // [object Arguments]
console.log(toString.call(symbol1));  // [object Symbol]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

终极检测方法

/**
 * @desc 数据类型检测
 * @param obj 待检测的数据
 * @return {String} 类型字符串
 */
function type(obj) {
  return typeof obj !== "object" ? typeof obj : Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}
1
2
3
4
5
6
7
8

数据类型的单独检测

/**
 * @desc 是否是 Undefined 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isUndefined(obj) {
    return obj === void 0;
}
/**
 * @desc 是否是 Null 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isNull(obj) {
    return obj === null;
}
/**
 * @desc 是否是 Boolean 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isBoolean(obj) {
    return typeof(obj) === 'boolean';
}
/**
 * @desc 是否是 Number 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isNumber(obj) {
    return typeof(obj) === 'number';
}
/**
 * @desc 是否是 String 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isString(obj) {
    return typeof(obj) === 'string';
}
/**
 * @desc 是否是 Object 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isObject(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]';
}
/**
 * @desc 是否是 Array 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isArray(obj){
    return Array.isArray?Array.isArray(obj):Object.prototype.toString.call(obj) === '[object Array]';
}
/**
 * @desc 是否是 Function 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isFunction(obj){
    return typeof(obj) === 'function';
}
/**
 * @desc 是否是 Date 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isDate(obj){
    return Object.prototype.toString.call(obj) === '[object Date]';
}
/**
 * @desc 是否是 RegExp 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isRegExp(obj){
    return Object.prototype.toString.call(obj) === '[object RegExp]';
}
/**
 * @desc 是否是 Error 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isError(obj){
    return Object.prototype.toString.call(obj) === '[object Error]';
}
/**
 * @desc 是否是 Arguments 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isArguments(obj){
    return Object.prototype.toString.call(obj) === '[object Arguments]';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

instanceof

为了更方便地鉴别引用类型,可以使用 JavaScript的instanceof 操作符。

nul instanceof Object; // false
obj instanceof Object; // true
arr instanceof Array; // true
fun instanceof Function; // true
date instanceof Date; // true
reg instanceof RegExp; // true
err instanceof Error;// true
arr instanceof Object; // true
1
2
3
4
5
6
7
8

每种引用类型的对象都被正确鉴别为 Object 的实例

其他

undefined == null // true
1
const symbol1 = Symbol();
const symbol2 = Symbol(42);
const symbol3 = Symbol('foo');

console.log(typeof symbol1);
// expected output: "symbol"

console.log(symbol3.toString());
// expected output: "Symbol(foo)"

console.log(Symbol('foo') === Symbol('foo'));
// expected output: false
1
2
3
4
5
6
7
8
9
10
11
12

鉴别数组

虽然 instanceof 可以鉴别数组,但是有一个例外会影响网页开发者:JavaScript 的值可以在同一个网页的不同框架之间传来传去。 当你试图鉴别一个引用值的类型时,这就有可能成为一个问题,因为每一个页面拥有它自己的全局上下文——Object、Array 以及其他内建类型的版本。结果,当你把一个数组从一个框架传到另一个框架时,instanceof就无法识别它,因为那个数组是来自不同框架的 Array 的实例。 为了解决这个问题,ECMAScript 5 引入了 Array.isArray()来明确鉴别一个值是否为 Array 的实例,无论该值来自哪里,该方法对来自任何上下文的数组都返回true。如果你的环境兼容 ECMAScript5,Array.isArray()是鉴别数组的最佳方法。

属性探测:判断属性是否存在

  1. 使用in操作符 in会检查自有属性和原型属性
console.log('name' in person) // true or false
1
  1. hasOwnProperty() 仅检查自有属性
var person1 = {
  name:'xinxin'
}

console.log('name' in person1); // true
console.log('toString' in person1); // true

console.log(person1.hasOwnProperty('name')); // true
console.log(person1.hasOwnProperty('toString')); // false
1
2
3
4
5
6
7
8
9

属性枚举:

可枚举属性

  1. for-in
  2. Object.keys() 获取可枚举属性数组

属性特征:

通用特征

  1. enumerable 是否可以遍历该属性
  2. configurable 该属性是否可配置

想改变属性特征的话,可以使用Objec.defineProperty()方法

var person = {
  name:'xinxin'
};
Object.defineProperty(person,'name',{
  enumerable:false
});
console.log(person.propertyIsEnumerable('name'));// false

Object.defineProperty(person,'name',{
  configurable:false
});
delete person.name;
console.log('name' in person); // true
console.log(person.name);// 'xinxin'
Object.defineProperty(person,'name',{ // Error
  configurable:false
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

从上述例子可看出无法将一个不可配置的属性改为可配置

数据属性特征

  1. value
  2. writable

属性访问器特征

  1. get
  2. set

最上层的原型对象Object.prototype有如下属性: [[Prototype]] : null hasOwnProperty:(function) propertyIsEnumerable:(function) isPrototypeOf:(function) toString:(function) valueOf:(function)

参考文档