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

本文涉及的产品
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
云原生大数据计算服务 MaxCompute,5000CU*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 
目录
相关文章
|
1月前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
1月前
|
JavaScript 前端开发 Java
springboot解决js前端跨域问题,javascript跨域问题解决
本文介绍了如何在Spring Boot项目中编写Filter过滤器以处理跨域问题,并通过一个示例展示了使用JavaScript进行跨域请求的方法。首先,在Spring Boot应用中添加一个实现了`Filter`接口的类,设置响应头允许所有来源的跨域请求。接着,通过一个简单的HTML页面和jQuery发送AJAX请求到指定URL,验证跨域请求是否成功。文中还提供了请求成功的响应数据样例及请求效果截图。
springboot解决js前端跨域问题,javascript跨域问题解决
|
12天前
|
存储 JavaScript 前端开发
JavaScript中的数据类型以及存储上的差别
通过本文的介绍,希望您能够深入理解JavaScript中的数据类型及其存储差别,并在实际编程中灵活运用这些知识,以提高代码的性能和稳定性。
41 3
|
1月前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
49 5
|
1月前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
40 2
|
1月前
|
缓存 前端开发 JavaScript
JavaScript前端路由的实现原理及其在单页应用中的重要性,涵盖前端路由概念、基本原理、常见实现方式
本文深入解析了JavaScript前端路由的实现原理及其在单页应用中的重要性,涵盖前端路由概念、基本原理、常见实现方式(Hash路由和History路由)、优点及挑战,并通过实际案例分析,帮助开发者更好地理解和应用这一关键技术,提升用户体验。
75 1
|
1月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
52 4
|
1月前
|
存储 JavaScript 前端开发
js中的数据类型
JavaScript 中的数据类型包括五种基本类型(String、Number、Undefined、Boolean、Null)和三种引用类型(Object、Array、Function,以及ES6新增的Symbol)。基本类型直接存储值,引用类型存储的是指向实际数据的内存地址。了解它们的区别对于掌握 JavaScript 的变量赋值和函数传参至关重要。
24 1
|
2月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
193 2
|
2月前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
56 0