前端基石:JS 中的9大数据类型和数据类型转换

简介: 本文主要讲JS 中的9大数据类型和数据类型转换

网络异常,图片无法展示
|


9大数据类型


网络异常,图片无法展示
|

数字中奇怪的值:

  • NaN:不是有效数字,但是是 number 类型。isNaN 是检测值是不是 NaN,在检查的时候,如果当前值不是数字类型,会先隐式转换为数字类型(Number 转换),然后在判断是否为有效数字。Object.is(NaN, NaN) 也可以检测值是否是 NaN


数据类型转换


在前端的类型转换中,分为两种:手动转换和隐式转换


其他类型转换为 Number 类型


  • 手动转换
  • Number([val])
  • parseInt/parseFloat([val])
  • 隐式转换(浏览器内部默认是先转换为 Number 在进行计算)
  • isNaN([val])
  • 数字运算(+、-、*、/、%),但是 + 运算在出现字符串的情况不是数字运算,是字符串拼接
  • 在进行 == 比较的时候,有些值需要转换为数字在比较


Number 转换


// 字符串转换为数字
Number('') => 0
Number('10') => 10
Number('10px') => NaN  // 只要出现非有效数字结构就是 NaN
// 布尔值转换为数字
Number(true) => 1
Number(false) => 0
// 其他类型转换为数组
Number(null) => 0
Number(undefined) => NaN
Number(Symbol(1)) => 报错
Number(BigInt(1)) => 1
对象转换为数字 => 先基于 valueOf 方法转换为原始类型,没有原始类型在基于 toString 转换为字符串,在将字符串转换为数字


parseInt/parseFloat 转换


parseInt 转换机制(parseFloat 类似,只是多识别一个小数点):

  1. 从字符串左侧的第一个字符串开始查找有效数字。
  2. 遇到非有效数字字符就停止查找,无论后面是否还有有效数字都不会再管。
  3. 把找到的有效数字字符转换为数字。
  4. 如果一个有效数字字符都么有找到,结果就是NaN。

看几个某大厂的面试题例子:输出结果是什么?


parseInt('');
Number('');
isNaN('');
parseInt(null);
Number(null);
isNaN(null);
parseInt('1px');
Number('1px');
isNaN('1px');
parseInt('1.1px') + parseFloat('1.1px') + typeof parseInt(null);
isNaN(Number(!!Number(parseInt('1.8'))));
typeof !parseInf(null) + !isNaN(null);
1 + false + undefined + [] + 'Tencent' + null + true + {};

并且对于 parseInt() 还有一个比较经典的面试题:

let arr = [1,2,3,4];
arr = arr.map(parseInt);
console.log(arr);


这里需要先搞清楚 parseInt([value], [radix])的规则:

  • [radix] 这个值是一个进制,不写或者写0默认都是按照10进制进行处理(特殊情况:如果 value 是以 0x 开头,则默认值是 10 或者 16)。
  • 进制有一个取值的范围,2~36 之间,如果不在这之间,整个程序运行结果一定是 NaN。
  • [value] 是 [radix] 进制的值,需要将 [value] 转换为 十进制。
arr.map(parseInt)
=> 
parseInt('1', 0);  => 1
parseInt('2', 1);  => NaN
parseInt('3', 2);  => NaN
parseInt('4', 3);  => NaN
=> [1, NaN, NaN, NaN]


隐式转换


看一个简单的例子:


[] == false;


对象和布尔的比较,都是转换为数字(隐式转换),对象转换为数字先基于 valueOf 获取原始值,如果没有原始值在去 toString 转换为字符串然后在转换为数字。


在上面的例子中:

  1. [] 基于 valueOf 获取原始值,[].valueOf() => [] ,发现 [] 没有原始值。
  2. [] 没有原始值就调用 toString 转换为字符串,[].toString() => ''。
  3. '' 转换为数字为 0 。
  4. false 转换为数字为 0。
  5. 所以 [] == false => true


在看一个扩展的例子:


![] == false;
  1. 这里的比较先看符号优先级,! 的优先级高于 == ,所以是 ![] 的结果在和 false 进行比较。
  2. ![] 的潜在意思就是将 [] 转换为布尔在取反。
  3. 在 js 中 ''、0、null、undefined、NaN 这五个值变成布尔为 false ,其他的值都是 true ,所以 [] 转换为布尔结果 为 true。 ![] => false。
  4. ![] == false 结构就是 true。

对象转换的规则,会先调用内置的 [ToPrimitive] 函数,其规则逻辑如下:

  • 如果部署了 Symbol.toPrimitive 方法,优先调用再返回;
  • 调用 valueOf(),如果转换为基础类型,则返回;
  • 调用 toString(),如果转换为基础类型,则返回;
  • 如果都没有返回基础类型,会报错。


其他类型转换为 String 类型


  • 手动转换
  • String([val])
  • toString()
  • 隐式转换
  • +运算,如果一边出现字符串,则是字符串拼接。
  • 这里有一种特殊的情况,如果出现对象的 + (例如:1+[])也会变成字符串拼接,原因在于对象转换为数字的过程中会先将对象转换为字符串,+ 遇到字符串就变成字符串的拼接了。
  • 对于 +/++ 这种不一定是字符串拼接,是运算。
  • 还有一种特殊情况 {} + 0 这种情况,左边貌似一个对象,但是在处理的时候会当做一个代码块在处理。所以结果是数字 0 。
  • 把对象转换为数字,需要先 toString() 转换为字符串,再去转换为数字


其他类型转换为 Boolean 类型


  • 手动转换
  • ![val]
  • !![val]
  • Boolean([val])
  • 隐式转换
  • 在循环或者条件判断中,条件处理的结果就是布尔类型值


数据类型检测



第一种判断方法:typeof


typeof 1 => 'number'
typeof '1' => 'string'
typeof treu => 'boolean'
typeof undefined => undefined
typeof null => 'object'
typeof Symbol(1) => 'symbol'
typeof 1n => 'bigint'
typeof []  =>'object'
typeof {}  =>'object'
typeof console  => 'object'
typeof console.log  => 'function'


typeof 的类型检测有两点需要注意:


  1. typeof null 结果是 'object',一般大家都说这是计算机的一个 Bug 导致的,但是到底是一个什么 Bug 导致了这个问题了?

“typeof null”错误是 JavaScript 第一版的遗留物。在这个版本中,值存储在 32 位单元中,由一个类型标签(1-3 位)和值的实际数据组成。类型标签存储在单元的低位中。其中有五个:

  • 000:对象
  • 1:整数
  • 010:浮点数
  • 100:字符串
  • 110:布尔值


也就是说,最低的位是一位,那么类型标记只有一位长。或者它是零,那么类型标签的长度是三位,为四种类型提供两个额外的位。有一个值比较特殊:

  • undefined 是整数 -2 ^30 (整数范围之外的数字)
  • null 是机器码 NULL 指针。一个对象类型标签加上一个为零的引用。 这就很明显为什么 typeof null 结果是 'object' 了。

并且在ECMA6中,曾经有提案为历史平凡,将 type null 的值纠正为 'null',但最后提案被拒了。理由是历史遗留代码太多。

  1. 引用数据类型 Object,用 typeof 来判断的话,除了 function ,其余都是 'object'。这也是为为什么在类型区分的时候,需要将 object 和 function 区分开的原因之一。

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


第二种判断方法:instanceof


[value] instanceof [constructor]

instanceof 运算符用来检测 [value] 在其原型链中是否存在一个 [constructor] 的 prototype 属性。


function myInstanceof(left, right) {
  // 先用 typeof 来判断基础数据类型,如果是,直接返回 false
  if(typeof left !== 'object' || left === null) return false;
  // 然后使用 getProtypeOf 获取参数的原型对象
  let proto = Object.getPrototypeOf(left);
  // 循环往下寻找,直到找到相同的原型对象
  while(true) {
    // 找到最顶层
    if(proto === null) return false; 
    // 找到相同原型对象,返回true
    if(proto === right.prototype) return true;
    // 继续向上寻找
    proto = Object.getPrototypeof(proto);
   }
}


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


第三种判断方法:constructor


[value].constructor === 类,相对于 instanceof 来讲基本类型也可以处理,而且因为获取实例的 constructor 实际上获取的是所属的类,所以在检测准确性上比 instanceof 还好一点,但是 constructor 是可以随意被改动的。


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


toString() 是 Object 的原型方法,调用该方法,可以统一返回格式为 “[object Xxx]” 的字符串,其中 Xxx 就是对象的类型。对于 Object 对象,直接调用 toString() 就能返回 [object Object];而对于其他对象,则需要通过 call 来调用,才能返回正确的类型信息。


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


通过 Object.prototype.toString 可以实现一个通过的类型判断方法:


function getType(obj){
  let type  = typeof obj;
  // 先进行typeof判断,如果是基础数据类型,直接返回
  if (type !== "object") {    
    return type;
  }
  // 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
  return Object.prototype.toString.call(obj).replace(/^[object (\S+)]$/, '$1'); 
}


在 ES3 中,在 toString 方法被调用时,会执行下面的操作步骤:


  1. 获取 this 对象的 [[Class]] 属性的值。
  2. 计算出三个字符串 "[object ",第一步的操作结果 Result(1),以及 "]" 连接后的新字符串。
  3. 返回第二步的操作结果 Result(2) .


在 ES5 中,在 toString 方法被调用时,会执行下面的操作步骤:


  1. 如果 this 的值为 undefined,则返回 "[object Undefined]"。
  2. 如果 this 的值为 null,则返回 "[object Null]"。
  3. 获取 ToObject(this) 的结果 Result(1)。
  4. 获取 Result(1) 的内部属性 [[Class]] 的值 Result(2)。
  5. 返回三个字符串"[object ", Result(2), 以及 "]"连接后的新字符串.


参考



相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps 
目录
相关文章
|
12小时前
|
前端开发 JavaScript
前端 js 经典:array 原生方法
前端 js 经典:array 原生方法
6 1
|
18小时前
|
缓存 前端开发 JavaScript
Javascript模块化开发基础,最新美团点评前端团队面试题
Javascript模块化开发基础,最新美团点评前端团队面试题
|
1天前
|
设计模式 存储 前端开发
JS的几种设计模式,Web前端基础三剑客学习知识分享,前端零基础开发
JS的几种设计模式,Web前端基础三剑客学习知识分享,前端零基础开发
|
1天前
|
移动开发 前端开发 JavaScript
前端高效开发JavaScript库!
前端高效开发JavaScript库!
|
2天前
|
Web App开发 前端开发 JavaScript
在 Chrome 开发者工具里配置哪些类型的 JavaScript 文件应该被调试器忽略
在 Chrome 开发者工具里配置哪些类型的 JavaScript 文件应该被调试器忽略
6 0
|
2天前
|
存储 JavaScript 前端开发
使用Vue.js构建交互式前端的技术探索
【5月更文挑战第12天】Vue.js是渐进式前端框架,以其简洁和强大的特性深受开发者喜爱。它聚焦视图层,采用MVVM模式实现数据与视图的双向绑定,简化开发。核心特性包括响应式数据绑定、组件化、模板系统和虚拟DOM。通过创建Vue实例、编写模板及定义方法,可以构建交互式前端,如计数器应用。Vue.js让复杂、交互式的前端开发变得更加高效和易维护。
|
2天前
|
JavaScript 前端开发
深入了解前端框架Vue.js的响应式原理
本文将深入探讨Vue.js前端框架的核心特性之一——响应式原理。通过分析Vue.js中的数据绑定、依赖追踪和虚拟DOM等机制,读者将对Vue.js的响应式系统有更深入的理解,从而能够更好地利用Vue.js构建灵活、高效的前端应用。
|
JavaScript 前端开发
JavaScript类型判断
JavaScript类型判断
115 0
JavaScript类型判断
|
JavaScript 前端开发
JavaScript专题之类型判断(下)
JavaScript专题系列第五篇,讲解更加复杂的类型判断,比如 plainObject、空对象、类数组对象、Window对象、DOM 元素等
153 0
JavaScript专题之类型判断(下)

热门文章

最新文章