前端基本功---JS数据类型知多少

在 JavaScript 编程中,我们经常会遇到边界数据类型判断,在大厂面试中,总是逃不过现场秀一段手写代码,此时往往需要考虑好代码的边界类型,让面试官看到你严谨的编程逻辑和深入思考的能力,面试才算加分!因此掌握它,看来还是很有必要的!

首先JS数据类型有如下图所示 8 种类型

5c5b26cb0f7edc718c12c1ec527adacc.png

以上又可分为基础类型引用类型

基础类型:undefined、Null、Boolean、Number、String、BigInt、Symbol

引用类型:统称为 Object 类型。细分的话,有:Object 类型、Array 类型、Date 类型、RegExp 类型、Function 类型  、Math  类型等。

依据存储方式不同,数据类型大致可以分成两类:

基础类型存储在栈内存,被引用或拷贝时,会创建一个完全相等的变量;

引用类型存储在堆内存,存储的是地址,多个引用指向同一个内存地址。

let a = {
  name: 'Miss U',
  age: 9
}


let b = a;
console.log(a.name);  //Miss U


b.name = 'Baby';
console.log(a.name);  //Baby
console.log(b.name);  //Baby

当b的name被修改后,a的name也随之改变,这里就体现了引用类型的“共享”的特性,即这两个值都存在同一块内存中共享,一个发生了改变,另外一个也随之跟着变化。

let a = {
  name: 'father',
  age: 80
}
function change(obj) {
  obj.age = 3;
  obj = {
    name: 'son',
    age: 18
  }
  return obj;
}


let b = change(a);  
console.log(b.age);    // 18
console.log(a.age);    // 3

15行输出 b.age = 18,16行输出3,这里跟你预想的是否一样呢?

数据类型检测 

在日常的业务开发中,经常会遇到 数据类型检测问题,当然也是面试中常问的,

比如:如何判断数组?怎么检测数据类型?等等。类似的题目会很多,而且在平常开发过程中我们也会经常用到。

数据类型的判断方法其实有很多种,比如 typeof 和 instanceof等,接下来就展开具体说一说。

第一种判断方法:typeof
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'
typeof 1n   // 'bigint'
typeof BigInt('1')  //  'bigint';
typeof Object(1n)  // 'object' 
typeof console  // 'object'
typeof console.log  // 'function'

抛出问题:此处 typeof  null 为什么是 'object' 呢?

简单来说,typeof null的结果为Object,它是从娘胎里带出来的bug,😂在javascript 的最初版本中,使用的 32位系统,js为了性能优化,使用低位来存储变量的类型信息。

02b5d6ca95959de93fbb3342ffafdf1b.png

在判断数据类型时,是根据机器码低位标识来判断的,而null的机器码标识为全0,而对象的机器码低位标识为000。所以typeof null的结果被误判为Object

那么问题来了,后续版本包括ES6为什么不修复这个bug呢?

这个问题问的好,其实Es6已有提案,被拒了,因为历史遗留代码太多了,改了容易得罪人😂,所以bug就成了feature了。

75b80c4e5fe8e913b17e70cb0431b375.png

注意:引用数据类型 Object,用 typeof 来判断的话,除了 function 会判断为 Function 以外,其余都是 'object',是无法判断出来的

第二种判断方法:instanceof

首先明确instanceof是干嘛的?

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);


console.log(auto instanceof Car);
// expected output: true


console.log(auto instanceof Object);
// expected output: true
  • String 和 Date 对象同时也属于Object 类型(他们是由 Object 类派生出来的)

console.log(String.prototype.__proto__ === Object.prototype)// true
console.log(Date.prototype.__proto__ === Object.prototype) // true
  • 如果通过 字面量 的方式创建字符串,那么无法通过 instanceof 判断某个变量是否是字符串

const str = 'aaaa'
console.log(str instanceof String) // false
console.log(str instanceof Object) // false
  • 通过 new 方式,是可以使用 instanceof 判断 变量是否是字符串。

const str = new String('aaa')
console.log(str instanceof String) // true
console.log(str instanceof Object) // true
console.log(str.__proto__ === String.prototype) // true

对于复杂数据类型 对象 和 数组,无论是通过字面量的方式创建,还是 new 的方式,都是可以通过 instanceof 来判断数据类型的

class Person {
  constructor(name) {
    this.name = name
    this.type = 'man'
  }
}


const p1 = new Person('小白')
const p2 = { name: '肉丝' }


console.log(p1)  //  { name: '小白', type: 'man' }
console.log(p2) // { name: '肉丝' }
console.log(p1 instanceof Person)  // true
console.log(p1 instanceof Object) // true
console.log(p2 instanceof Object)  // true
const arr1 = [1, 2]
const arr2 = new Array('a', 'b')
console.log(arr1 instanceof Array) // true
console.log(arr2 instanceof Array) // true

那么问题又来了,如果让我们自己实现一个 instanceof 的底层实现,应该怎么写呢?

91fda2a91f86be3f05ab312166558154.png

此刻,双手🙌🏻呈上代码,如写的不对,欢迎指错。

function myInstanceof(obj, objType) {
  // 首先用typeof来判断基础数据类型,如果是,直接返回false
  if(typeof obj !== 'object' || obj === null) return false;
 
  // getProtypeOf是Object对象自带的API,能够拿到参数的原型对象
  let proto = Object.getPrototypeOf(obj);


  while(true) {  //循环往下寻找,直到找到相同的原型对象
    if(proto === null) return false;
    if(proto === objType.prototype) return true;//找到相同原型对象,返回true
       proto = Object.getPrototypeof(proto);
    }
}


// 验证myInstanceof
console.log(myInstanceof(new Array('2','3'), Array));    // true
console.log(myInstanceof(123, Number));                // false
console.log(myInstanceof(new Number(123), Number));   //true

总结一下:

  1. instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型;

  2. typeof 它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了 function 类型以外,其他的也无法判断。

    所以工作中常常需要结合这两个一起去检测数据类型,未免显得有些繁琐,所以,我一般更推荐第三种方法。


第三种判断方法:Object.prototype.toString

对于 Object.prototype.toString() 方法,会返回一个表示该对象的字符串,格式如"[object XXX]" 注意,XXX的首字母大写哦。

Object.prototype.toString.call(null)   //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(1)    // "[object Number]"
Object.prototype.toString.call('Miss U')  // “[object String]"
Object.prototype.toString.call(true)  // "[object Boolean]"
Object.prototype.toString({})       // "[object Object]"
Object.prototype.toString.call({})  // "[object Object]"
Object.prototype.toString.call(function(){})  // ”[object Function]"
Object.prototype.toString.call([])       //"[object Array]"
Object.prototype.toString.call(/123/g)    //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"
Object.prototype.toString.call(document)  //[object HTMLDocument]"
Object.prototype.toString.call(window)   //"[object Window]"

OK,最后,给大家呈上一段通用检测数据类型的方法

function getPrototype(obj){
  let type  = typeof obj;
  if (type !== "object") {    // 先进行typeof判断,如果是基础数据类型,直接返回
    console.log(obj,':',res)
    return type;
  }
  // 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
  const res = Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1')
  console.log(obj,'=',res);
  return res;
}
getPrototype([])     // "Array" typeof []是object,因此toString返回
getPrototype('abc')  // "string" typeof 直接返回
getPrototype(window) // "Window" toString返回
getPrototype(null)   // "Null"首字母大写,typeof null是object,需toString来判断
getPrototype(undefined)   // "undefined" typeof 直接返回
getPrototype()            // "undefined" typeof 直接返回
getPrototype(function(){}) // "function" typeof能判断,因此首字母小写
getPrototype(/123/g)      //"RegExp" toString返回

721acb96d27ab391a7de3a5e126eefa8.png

好了,今天的内容就分享到这,感谢观看!

⭐️⭐️山河远阔,国泰民安,祖国生日快乐!

     ae490590c3ddd9c8dc9de9bf491672bf.png

— END —

听说早在中秋节过后就有小伙伴调侃:“一点也不想干活,好想早点为我们祖国母亲庆生!”

0ceeaea747642c7b37b418e6069e09db.png

据说现在“爱国”三大表现是酱紫的

☟☟☟

1.祖国母亲生日临近,完全无心工作,只想为母亲庆生

2.觉得七天根本不足以表达我对祖国母亲的爱

3.希望祖国母亲过完这次生日后,再过个农历哒

不管你们是不是,反正我是中枪了…😄

5c6e0552656d17606c8959d8c37f2006.png

其实我们应该觉得很幸福了,当一个假期接着另一个假期的时候是很有盼头的!我们祖国母亲马上 就过生日了,而我们也迎来了今年最后一个大假!

回家

旅游

学习

这个假期你打算怎么安排呢?

相信现在的你已经安排好自己的国庆假期了,来吧,保持队型,跟上节奏,留言区共享一下你的国庆假期是怎么安排的?

参考资料:

https://kaiwu.lagou.com/course/courseInfo.htm?courseId=601#/detail/pc?id=6174

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值