[JS基础回顾] 数据类型判断方法~~~汇总

405 阅读4分钟

目录

  1. 8种数据类型
  2. typeof 无法区分 [] {} null
  3. instanceof 只能用于判断对象是否从属关系
  4. constructor 会被改写 判断类型不准确
  5. Object.prototype.toString.call/apply最准确`
  6. ECMA 封装的类型判断 isArray

一 8种数据类型

JS 是一种弱类型或者说动态类型,这就意味着你不需要提前声明变量的类型,在程序运行的过程中类型会被自动确定。这就意味着你可以使用同一个变量保存不同类型的数据

var a = 1; // Number
a = '1';  // String
a = [1];  // Array
a = {a:1};  // Object

1) 8 种数据类型

  1. 值类型(栈内存)
  2. 引用类型(栈内存(指针)->堆内存)

最新的 ECMAScript 标准定义了 8 种数据类型:

  • (值类型)7中原始类型:

    • Number
    • String
    • Boolean
    • Null
    • Undefined
    • BigInt
    • Symbol
  • (引用类型) Object

2) Symbol

Symbol 是ES6新增的一种基本数据类型。我们可以通过调用内置函数 Symbol() 创建,这个函数会动态的生成一个匿名、全局唯一的值

var a = Symbol();
var b = Symbol();
a === b // false

var c = Symbol('c'); // Symbol(c)

Symbol 函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是对象。可以接受一个字符串作为参数,为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。

var c = new Symbol('c');

image.png

3) 基本数据和引用数据的区别

3.1) 基本数据类型
  • 按值访问,可操作保存在变量中实际的值
  • 值被保存在 栈内存 中,占据固定大小的空间
3.2) 引用数据类型
  • 引用类型的值是按引用访问的
  • 保存在堆内存中的对象,不能直接访问操作对象的内存空间

typeof 无法区分 [] {} null

typeof 命令可以判断所有 JS 中的基本数据类型(Null, Undefined, Boolean, String, Number), 虽然 null 使用 typeof 返回的是 object 字符串, 但是无碍 它的基本使用, 但是在一些复杂的场景比如 object 与 null, array 与 object, function 与 object 等等的类型区分, typeof 就会显得心有余力不足了.

typeof 1; // 'number'
typeof '1'; // 'string'
typeof null; // 'object'
typeof undefined; // 'undefined'
typeof true; // 'boolean'
typeof Symbol('11') // 'symbol'
typeof 1n; // 'bigint'
typeof {} // 'object'
typeof [1]; // 'object'
typeof new Function() // 'function'

注意:

typeof {} // 'object' 
typeof [] // 'object' 
typeof(() => {}) // 'function'
typeof 'a'                 // 'string'
typeof new String('a')     // 'object'
typeof undefined   // 'undefined'
typeof null  // 'object'
typeof Symbol() // 'symbol'

三 instanceof 只能用于判断对象是否从属关系

  • 只能用来判断(两个对象是否属于原型链的关系)不一定能获取对象的具体类型
  • Instanceof 不适用判断原始类型的值只能用于判断对象是否从属关系
[1] instanceof Array; // true
[1] instanceof Object; // true

function a(){}
var b = new a();

b instanceof a; //true
b instanceof Object; //true

1) 注意:空对象{}的判断问题

let obj1 = {}
obj1 instanceof Object // true

let obj2 = Object.create(null)
obj2 instanceof Object; // false

let obj222 = Object.create(Object)
obj222 instanceof Object; // true

let obj3 = Object.create({})
obj3 instanceof Object; // true

constructor 会被改写 判断类型不准确

每一个实例对象都可通过constructor来访问它的构造函数,其实也是根据原型链的原理来的。

(new Function).constructor === Function; // true
(1).__proto__.constructor === Number; // true
(1).constructor === Number; // true
'1'.constructor === String; // true
'1'.__proto__.constructor === String; // true
[1].__proto__.constructor === Array; // true

var abc = new RegExp();
abc.constructor === RegExp; // true

由于 undefined 和null是无效的对象因此是没有constructor属性的,这两个值不能用这种方法判断.


undefined.__proto__.constructor // Cannot read property '__proto__' of undefined

null.__proto__.constructor // Cannot read property '__proto__' of undefined

注意: constructor 会被改写,因此判断类型也是不准确的

[1].__proto__.constructor = String;
[1].__proto__.constructor === Array; // false

Object.prototype.toString.call/apply最准确`

  • Object.prototype.toString方法返回对象的类型字符串最准确
  • 因为实例对象有可能会自定义toString方法,会覆盖Object.prototype.toString,所以在使用时,最好加上call
Object.prototype.toString.apply('5') // '[object String]'
Object.prototype.toString.call('5') // '[object String]'
Object.prototype.toString.call(5) // '[object Number]'
Object.prototype.toString.call([5]) // '[object Array]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(new Function()); // '[object Function]'
Object.prototype.toString.call(new Date()); // '[object Date]'
Object.prototype.toString.call(new RegExp()); // '[object RegExp]'
Object.prototype.toString.call(new Error()); // '[object Error]'

Object.prototype.toString.call(null).slice(8, -1) // "Null" Object.prototype.toString.call(3).slice(8, -1) // "Number"

isArray判断null undefined

Array.isArray([]); // true
var isNull = function (obj) {
    return obj === null;
};
isNull(null); // true
var isUndefined = function (obj) {
	return obj === void 0; // void null // void undefined
}
isUndefined(undefined); // true

1) 转字符串

String(null)                 // 'null'
String(undefined)            // 'undefined'
String(true)                 // 'true'
String(1)                    // '1'
String(-1)                   // '-1'
String(0)                    // '0'
String(-0)                   // '0'
String(Math.pow(1000,10))    // '1e+30'
String(Infinity)             // 'Infinity'
String(-Infinity)            // '-Infinity'
String({})                   // '[object Object]'
String([1,[2,3]])            // '1,2,3'

参考

总结

  • Symbol 通过调用内置函数 Symbol() 创建,这个函数会动态的生成一个匿名、全局唯一的值

  • Symbol 最大的用处就是:避免对象的键被覆盖

  • typeof 无法区分 [] {} null

  • Instanceof 不适用判断原始类型的值只能用于判断对象是否从属关系

  • constructor 会被改写,因此判断类型也是不准确的

  • instanceof 适合自定义对象,也可以用来检测原生对象,在不同的iframe 和 window间检测时失效,还需要注意Object.create(null)对象的问题

  • constructor 基本能判断所有类型,除了null和undefined,但是constructor容易被修改,也不能跨iframe使用

  • Object.prototype.toString.apply 能判断所有类型,最准确