数据类型

299 阅读5分钟

1. 概要

作为解释性语言,和其他高级语言一样,也拥有数据类型。 总体分为两大类, 一是基本类型,二是引用类型。关于二者的区分请参照文 堆栈存储 · 语雀,这篇文章详细的介绍了。

五大基本类型分别是 null、number、undefined、string、boolean 外加 es6 中的 symbol, 一共 6 种基本数据类型。其中 null 和 undefined 都空,但两者存在明显的差别,null 表示空, undefined 表示未初始化任何值。

引用类型较复杂,总的来说除了基本类型外都是引用类型,在 javascript 中,一切皆对象, BOM、DOM、Object、Array 等均属于引用类型。

2. 类型检查

前端数据类型检查,通常我们使用 typeof、instanceof、constructor、isPrototypeOf、Object.prototype.toString.call 等多种方式检查数据类型。推荐使用 Object.prototype.toString.call 这种方式检查数据类型。下面分别对这接种方式做探讨。

2.1 typeof

typeof 是类型运算符,通过此运算符可以得到相应的数据类型,并且返回数据类型的字符串形式,如: typeof true 返回 string,能准确得到除 null 之外的基本类型数据的相应字符串形式。但不能准确得到引用类型数据类型,引用类型均返回 object强调,typeof 得到的结果是数据类型的 字符串形式

typeof 1; // 'number';
typeof '1'; // 'string';
typeof undefined; // 'undefined'
typeof true; // 'boolean'
typeof Symbol(); // 'symbol'
typeof null; // 'object'
typeof ( () => {} ); // 'function'
typeof {}; // 'object'
typeof []; // 'object'
typeof new Set(); // 'object'
typeof new Map(); // 'object'

2.2 instanceof

instanceof 用于检测数据是否为某一实体类的实例,如果是返回 true,否则返回 false。在 js 中,Object 是基础类, 所有的实例最终是 Object 的实例。即如果发生了继承关系,在父类和祖先类中同样返回 true。

[] instanceof Array; // true
[] instanceof Object; // true, Array extend Object 
({}) instanceof Object; // true

2.3 constructor

constructor 构造器是对象属性,如果是内置对象则返回原生本地代码,非内置对象则返回构造器函数(构造函数), 可以把 constructor 理解成指针。

/* 内置对象 */
[].constructor; // ƒ Array() { [native code] }
(1).constructor; // ƒ Number() { [native code] }
(true).constructor; // ƒ Boolean() { [native code] }
({}).constructor; // ƒ Object() { [native code] }

/* 非内置对象(自定义)*/
function Constructor(){};
const co = new Constructor(); // Constructor {name: 'constructor'}

2.4 isPrototypeOf

测试一个对象是否存在于另一个对象的原型链上(检测一个对象是否是另一个对象的原型对象) ,如果是则返回 true,否则返回 false isPrototypeOf,在 es5 之前没有该方法,可以通过 __proto__ 进行判断。

function Foo(){};
const foo = new Foo();
Foo.prototype.isPrototypeOf( foo ); // true, Foo 的原型是否是 foo 对象的原型对象

// 使用 __proto__ 
foo.__proto__ === Foo.prototype // true

2.5 Object.prototype.toString

定义类型检查方法,通过次方法可以检查任何数据类型的 toString 形式, 如 DOM、 BOM等对象。以下方法通过原型链扩展方式扩展了,isFunction、isNumber、isArray、isNull 等常用数据类型检查函数,方便逻辑判断和处理。

// 定义获取数据类型的函数
const getType = (data: any): string => Object.prototype.toString.call(data)
    .replace(/^[object\s+(.+)]$/, '$1' )
    .toLowerCase();
getType( null ); // null
getType( [] ); // array
getType( {} ); // object
getType( '蓝天' ); // string
getType( true ); // boolean
getType( undefined ); // undefined
getType( () => {} ); // function

完整的封装逻辑

// dataTypes.js
// 定义类型检查模块
export const dataTypes = [ 
  "Boolean", 
  "Number", 
  "String",
  "Undefined",
  "Null",
  "Function",
  "Array",
  "Date",
  "RegExp",
  "Object",
  "Error",
  "Symbol",
  "Set",
  "Map",
  "Promise",

  // BOM
  "Location",
  "Window",
  "Navigator",
  "ApplicationCache",
  "CacheStorage",
  "Storage",
  "History",
  "IDBFactory",
  
  // DOM
  "HTMLDocument",
]
import { dataTypes } from './dataTypes';
class Class2type{ 
  constructor(){
    this.__proto__.dataTypes = dataTypes;
  }
  /**
   * 功能:获取数据类型
   * 参数:opt, 数据对象; shift, 切换类型大小写, 默认值值 false 首字母大写
   * 返回值:数据类型
   */
  getType( opt, shift = false ){
    const typeStr = Object.prototype.toString.call( opt ).replace( /^[object\s+(.+)]$/, '$1' );
    return shift ? typeStr.toLowerCase() : typeStr
  }
}
const class2type = new Class2type();
class2type.dataTypes.forEach( item => {
  Object.assign( Class2type.prototype, {
    [ 'is' + item ]( opt ){
      return class2type.getType( opt ) === item;
    }
  })
});
export default Class2type;
export const { 
  isBoolean, 
  isNumber, 
  isString,
  isUndefined,
  isNull,
  isFunction,
  isArray,
  isDate,
  isRegExp,
  isObject,
  isError,
  isSymbol,
  isSet,
  isMap,
  isPromise,
  
  getType,
} = class2type;

2.6 其他

// 检测数据是否为数组
Array.isArray([]); 

// 检测数据是否被定义过
const isNotExist = param => param == null 

// 检测对象是否为空
const isEmptyObject = param => Object.keys( param ).length === 0; 

3. 类型转换

各类型数据之间的运算,不同数据类型之间相互转换等遵循的规则,如果是基本类型则按照执行的先后顺序运算;如果是引用类型先执行toString方法再进行运算,像 null、undefined 没有toString方法,运算的结果是数值或字符串字。在 es6 中的数据类型 symbol 不能与其他数据类型进行运算操作。

3.1 转成数值

布尔与数值是一对好兄弟通常我们使用 0 表示 false,1 表示 true。所以在布尔值和数值进行运算的时,布尔值总是转成数值(0或1)。null 通常表示空,什么也没有, 转成数值是 0。

// 转换成数值
true + 1; // 2
false + 1; // 1
1 + false; // 1
1 + true; // 2

true + null; // 1
true + undefined; // NaN

1 + null; // 1
null + 1; // 1

true + false + 1 + 0 + null + undefined; // NaN, 最终是 number 类型

3.2 转成字符串

运算中出现字符串,或者出现了引用类型的数据运算,引用类型的数据在进行运算时会先执行toString方法后再进行运算。运算按先后顺序执行,

true + ''; // 'true'
// 顺序执行
1 + 1 + '2' + 1; // '221'
'2' + 1 + 1 + 1; // 2111

null + ''; // 'null'
undefined + ''; // 'undefined'


[ 1, 2 ] + true; // '1,2true'

true + {}; // true[object Object]
{} + true; // 1 

💡 true + {}{} + true,前一个执行的结果符合我们的预期,而后面的一个则出乎意料。在执行后面的语句的时候,{} 是作为一个独立的代码块执行的,只是这个独立的代码块中没有任何代码,可以理解成{}; + true, 这样输出 1 则就是正常的了, 它的最终值取决于+true

附录

创作不易,欢迎打赏。你的支持,是我持续创作的动力哦。如果文章表述不清或错误,欢迎大家留言。我会及时反馈给大家,希望帮助到大家。