【前端进阶】JS中的数据类型

基本数据类型(值类型,原始数据类型)

number

let num1 = 10; // 整型
let num2 = 10.00; // 浮点型
let num3 = NaN; // 非数字值的特殊值
let num4 = Infinity; // 无穷大

string

let str1 = 'str'; // 单引号包裹
let str2 = "str"; // 双引号包裹
let str3 = `str`; // 模板字符串

boolean

let boo1 = true; // 正确
let  boo2 = false; // 错误

null

let nul = null; // 对象的值未设置

undefined

typeof undefined // undefined不是常量,而是指变量未定义

symbol

let big= Symbol(1); // 唯一值,可作为对象属性的标识符

bigint

let big= 10n; // 大数

引用数据类型

object

let obj1= new Object() || {}; // 普通对象
let obj2= new Array() || []; // 数组对象
let obj3= new RegExp('^obj$') || /^obj$/; // 正则对象
let obj4= new Date(); // 日期对象
let obj5= new Set(); // set对象
let obj5= new Map(); // map对象
...

function

let fn1= function(){}; // 普通函数/构造函数
let  fn2= ()=>{}; // 箭头函数
let fn3 = function*(){}; // 生成器函数
...

数据类型检测

为了方便,以下所有需打印的代码省略了console.log()

typeof

按照计算机底层储存的二进制结果进行检测,对象都以000开始的,null的二进制储存结果为000000

  1. 检测数据类型的运算符
  2. 返回类型是字符串,字符串中包含对应的数据类型
  3. 所有对象基于typeof的检测都是"object",因此typeof无法检测对象的具体细分
// 检测数据类型的运算符
typeof 10 // "number"
typeof 'str' // "string"
typeof true // "boolean"
typeof null // "object"=>null的二进制储存结果为000000
typeof undefined // "undefined"
typeof Symbol(1) // "symbol"
typeof 10n // "bignit"
typeof function(){} // "function"

// 返回类型是字符串
typeof typeof xxx // "string"

// 所有对象基于typeof的检测都是"object",因此typeof无法检测对象的具体细分
typeof new Object() // "object"
typeof new Array() // "object"
typeof new RegExp('^obj$') // "object"
typeof new Date() // "object"
typeof new Set() // "object"
typeof new Map() // "object"
...

instanceof

用来检测当前实例是否属于这个类

  1. 一般用来检测对象的具体细分
  2. 无法检测普通对象
  3. 无法检测原始数据类型
  4. 检测时,浏览器会调用Function原型上的Symbol.hasInstance()方法
// 无法检测普通对象
let arr = [];
arr instanceof Array; // true
arr instanceof RegExp; // false
arr instanceof Object; // true

// 无法检测原始数据类型
let n = 10,// 原始数据类型
    m = new Number(10); // 引用数据类型
n instanceof Number; // false
m instanceof Number; // true

// 手动改变原型指向导致检测不正确
function Person(){}
Person.prototype = Array.prototype;
let p1 = new Person;
p1 instanceof Array // true

// 检测时,浏览器会调用Function原型上的Symbol.hasInstance()方法
// 原理:检测当前实例的原型链(__proto__)上是否存在这个类的原型(prototype)
arr instanceof Array // true
=>Array[Symbol.hasInstance](arr) // true

constructor

用来获取当前实例的构造函数

  1. 比instanceof好用一点
  2. 可以检测原始数据类型
  3. constructor可以随意修改,所以也不准确
// 比instanceof好用一点
let arr = [];
arr.constructor === Array; // true
arr.constructor === RegExp; // false
arr.constructor === Object; // false

// 可以检测原始数据类型
let n = 10,// 原始数据类型
    m = new Number(10); // 引用数据类型
n.constructor === Number; // true
m.constructor === Number; // true

// constructor可以随意修改,所以也不准确
function Person(){}
Person.prototype.constructor = Array;
let p1 = new Person;
p1.constructor === Array // true

Object.prototype.toString.call()

专门用来检测数据类型

  1. Number/String/Boolean/Symbol/Bigint/Function/Array/RegExp/Date…上原型都有toString方法,用来转化为字符串
  2. Object原型上的toString专门用来检测数据类型
  3. 返回结果:"[obejct 对象[Symbol.toStringTag] || 对象,构造函数 (不受自己更改的影响)|| Object]"
// Number/String/Boolean/Symbol/Bigint/Function/Array/RegExp/Date...上原型都有toString方法,用来转化为字符串
(10).toString() // "10"
"str".toString() // "str"
true.toString() // "true"
Symbol(1).toString() // "Symbol(1)"
10n.toString() // "10"
(function(){}).toString() // "function(){}"
[1,2].toString() // "1,2"
/^test$/.toString() // "/^test$/"
new Date().toString() // "Sat Oct 17 2020 14:58:09 GMT+0800 (中国标准时间)"
...

// Object原型上的toString专门用来检测数据类型
var toString = Object.prototype.toString;
toString.call(10) // "[object Number]"
toString.call('str') // "[object String]"
toString.call(true) // "[object Boolean]"
toString.call(null) // "[object Null]"
toString.call(undefined) // "[object Undefined]"
toString.call(Symbol(1)) // "[object Symbol]"
toString.call(10n) // "[object BigInt]"
toString.call(new Object()) // "[object Object]"
toString.call(new Array()) // "[object Array]"
toString.call(new Date()) // "[object Date]"
toString.call(new RegExp()) // "[object RegExp]"
toString.call(new Set()) // "[object Set]"
toString.call(new Map()) // "[object Map]"
toString.call(function(){}) // "[object Function]"
toString.call(function*(){}) // "[object GeneratorFunction]"
...

重写instanceof

// obj:要检测的实例,不能为原始类型
// ctor:要检测的类,必须为函数
function instanceOf(obj,ctor){

	// 如果obj为null或者obj不是对象或方法则返回false
	if(typeof obj === null || !/^(object|function)$/i.test(typeof obj))return false;
	
	// 如果ctor不是一个类,则报错
	if(typeof ctor !== 'function') throw new TypeError('Right-hand side of "instanceof" is not an object');
	
	// Object.getPrototypeOf(obj)===obj.__proto__
	let proto = Object.getPrototypeOf(obj),
        prototype = ctor.prototype ;
        
    // 在该实例的原型链当中查找此类的原型
    while(true){
        // 如果一直找到Object.prototype.__proto__,则该实例不属于此类
        if(proto === null ) return false;
        // 该实例原型链中可以找到此类的原型,则该实例属于此类
        if( proto === prototype ) return true;
        // 往上逐级查找
        proto = Object.getPrototypeOf(proto);
    }

}

JQ中关于数据类型检测的源码封装

const class2type = {},
    toString = class2type.toString, // Object.prototype.toString 用于检测数据类型
    hasOwn = class2type.hasOwnProperty, // Object.prototype.hasOwnProperty 用于检测私有属性
    fnToString = hasOwn.toString, // Function.prototype.toString 用于转换为字符串
    ObjectFunctionString = fnToString.call(Object), // "function Object() { [native code] }"
    getproto = Object.getprototypeof; // 用于获取原型链

// 类型映射表
const typeList = 'Number String Boolean Symbol Bigint Function Object Date RegExp Array Error'.split(' ').forEach((item) => {
    class2type[`[object ${item}]`] = item.toLowerCase();
})

//公共判断类型方法
const toType = function toType(obj) {

	// 如果为null/undefined 则返回"null"/"undefined"
    if (obj == null) {
        return obj + '';
    }
    
    // 如果obj为方法或者对象,则以toString.call(obj)为key在类型映射表中查找对应value,有则返回value,没有则返回'object'。
    // 否则用typeof判断obj的数据类型
    return typeof obj === 'function' || typeof obj === 'object' ? class2type[toString.call(obj)] || 'object' : typeof obj
}

// 是否是函数
const isFunction = function isFunction(obj) {
    return typeof obj === 'function' && typeof obj.nodeType !== 'number';
}

// 是否是window
const isWindow = function isWindow(obj) {
    return obj != null && obj === obj.window;
}

// 是否为数组或类数组
const isArrayLike = function isArrayLike(obj) {
    const length = !!obj && 'length' in obj && obj.length,
        type = toType(obj);

    if (isFunction(obj) || isWindow(obj)) {
        return false;
    }
    return type === 'array' || length === 0 || typeof length === 'number' && length > 0 && (length - 1) in obj;
}

// 是否为纯对象
const isPlainObject = function isPlainObject(obj) {
    let proto, ctor, type = toType(obj);
    if (!obj || type !== 'object') {
        return false;
    }

    proto = getproto(obj)
    if (!proto) {
        return true
    }

    ctor = hasOwn.call(proto, 'constructor') && proto.constructor;
    return typeof ctor === 'function' && fnToString.call(ctor) === ObjectFunctionString;
}

// 是否为空对象
const isEmptybject = function isEmptybject(obj) {
    const keys = [
        ...Object.getOwnPropertyNames(obj),
        ...Object.getOwnPropertySymbols(obj)
    ]
    return keys.length === 0
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值