前端基石: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 
目录
相关文章
|
13天前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
13天前
|
移动开发 前端开发 JavaScript
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
于辰在大学期间带领团队参考网易游戏官网的部分游戏页面,开发了一系列前端实训作品。项目包括首页、2021校园招聘页面和明日之后游戏页面,涉及多种特效实现,如动态图片切换和人物聚合效果。作品源码已上传至CSDN,视频效果可在CSDN预览。
21 0
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
|
18天前
|
JavaScript 前端开发 开发者
前端框架对比:Vue.js与Angular的优劣分析与选择建议
【10月更文挑战第27天】在前端开发领域,Vue.js和Angular是两个备受瞩目的框架。本文对比了两者的优劣,Vue.js以轻量级和易上手著称,适合快速开发小型到中型项目;Angular则由Google支持,功能全面,适合大型企业级应用。选择时需考虑项目需求、团队熟悉度和长期维护等因素。
25 1
|
19天前
|
JavaScript 前端开发 API
前端框架对比:Vue.js与Angular的优劣分析与选择建议
【10月更文挑战第26天】前端技术的飞速发展让开发者在构建用户界面时有了更多选择。本文对比了Vue.js和Angular两大框架,介绍了它们的特点和优劣,并给出了在实际项目中如何选择的建议。Vue.js轻量级、易上手,适合小型项目;Angular结构化、功能强大,适合大型项目。
17 1
|
22天前
|
前端开发 JavaScript UED
"前端小技巧大揭秘:JS如何将后台时间戳秒变亲切小时前、分钟前,让用户秒懂,提升互动体验!"
【10月更文挑战第23天】在Web开发中,将后台返回的时间戳转换为“小时前”、“分钟前”、“刚刚”等友好的时间描述是常见需求。本文介绍如何用JavaScript实现这一功能,通过计算当前时间和时间戳的差值,返回相应的描述,提升用户体验。
25 1
|
29天前
|
前端开发 JavaScript 安全
JavaScript前端开发技术
JavaScript(简称JS)是一种广泛使用的脚本语言,特别在前端开发领域,它几乎成为了网页开发的标配。从简单的表单验证到复杂的单页应用(SPA),JavaScript都扮演着不可或缺的角色。
20 3
|
1月前
|
存储 JavaScript 前端开发
JavaScript 数据类型详解:基本类型与引用类型的区别及其检测方法
JavaScript 数据类型分为基本数据类型和引用数据类型。基本数据类型(如 string、number 等)具有不可变性,按值访问,存储在栈内存中。引用数据类型(如 Object、Array 等)存储在堆内存中,按引用访问,值是可变的。本文深入探讨了这两种数据类型的特性、存储方式、以及检测数据类型的两种常用方法——typeof 和 instanceof,帮助开发者更好地理解 JavaScript 内存模型和类型检测机制。
71 0
JavaScript 数据类型详解:基本类型与引用类型的区别及其检测方法
|
1月前
|
存储 JavaScript 前端开发
JavaScript数据类型全解:编写通用函数,精准判断各种数据类型
JavaScript数据类型全解:编写通用函数,精准判断各种数据类型
19 0
|
1月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
131 2
|
1月前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
38 0