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