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

本文涉及的产品
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
简介: 本文主要讲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 
目录
相关文章
|
15天前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
28天前
|
JavaScript 前端开发 开发者
如何在 JavaScript 中处理不同类型的错误?
【10月更文挑战第29天】通过对不同类型错误的准确识别和恰当处理,可以提高JavaScript程序的可靠性和稳定性,减少错误对程序运行的影响。
|
26天前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
26天前
|
移动开发 前端开发 JavaScript
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
于辰在大学期间带领团队参考网易游戏官网的部分游戏页面,开发了一系列前端实训作品。项目包括首页、2021校园招聘页面和明日之后游戏页面,涉及多种特效实现,如动态图片切换和人物聚合效果。作品源码已上传至CSDN,视频效果可在CSDN预览。
31 0
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
|
27天前
|
JavaScript 前端开发 Java
除了 JavaScript,还有哪些编程语言支持 Set 类型
【10月更文挑战第30天】这些编程语言中的 `Set` 类型虽然在语法和具体实现细节上有所不同,但都提供了类似的集合操作功能,方便开发者在不同的编程场景中处理集合相关的数据和逻辑。
|
28天前
|
存储 JavaScript 前端开发
js的基础类型和引用类型
【10月更文挑战第29天】理解 JavaScript 中的基础类型和引用类型的区别对于正确地编写代码和理解程序的行为非常重要。在实际开发中,需要根据具体的需求合理地选择和使用不同的数据类型,以避免出现一些意想不到的错误和问题。同时,在处理引用类型数据时,要特别注意对象的引用关系,避免因共享引用而导致的数据不一致等问题。
|
1月前
|
JavaScript 前端开发 开发者
前端框架对比:Vue.js与Angular的优劣分析与选择建议
【10月更文挑战第27天】在前端开发领域,Vue.js和Angular是两个备受瞩目的框架。本文对比了两者的优劣,Vue.js以轻量级和易上手著称,适合快速开发小型到中型项目;Angular则由Google支持,功能全面,适合大型企业级应用。选择时需考虑项目需求、团队熟悉度和长期维护等因素。
40 1
|
1月前
|
JavaScript 前端开发 API
前端框架对比:Vue.js与Angular的优劣分析与选择建议
【10月更文挑战第26天】前端技术的飞速发展让开发者在构建用户界面时有了更多选择。本文对比了Vue.js和Angular两大框架,介绍了它们的特点和优劣,并给出了在实际项目中如何选择的建议。Vue.js轻量级、易上手,适合小型项目;Angular结构化、功能强大,适合大型项目。
29 1
|
5月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
100 2
|
5月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的小区物流配送系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的小区物流配送系统附带文章源码部署视频讲解等
136 4