【FuckingJavaScript系列】数据类型,你真的掌握了吗?

前言

工欲善其事,必先利其器。

大家好,我是龙哈哈。一个 JavaJavaScript 两栖动物。
本篇是FuckingJavaScript系列的第一篇,我们来一起回顾一下数据类型的相关知识。

JavaScript 是一种 弱类型 或者叫 动态 语言,函数式编程面向对象编程的混合产物。开发者不用提前声明变量的类型,在程序运行过程中,类型会被自动确定,同一个变量可以保存不同类型的数据。

var foo = 42;    // foo is a Number now
foo = "bar"; // foo is a String now
foo = true;  // foo is a Boolean now
复制代码

数据类型

最新的 ECMAScript 标准定义了 9 种数据类型,包括了原始数据类型复杂数据类型

原始数据类型

  • String
  • Boolean
  • Number
  • Undefined
  • Symbol
  • Bigint

String

字符串类型,用于表示文本数据。
JavaScript 字符串是不可更改的。这意味着字符串一旦被创建,就不能被修改。但是,可以基于对原始字符串的操作来创建新的字符串。

  • 字符串截取String.substr()
  • 字符串拼接String.concat()

Boolean

布尔类型,只有两个值 truefalse,用于表示逻辑真与假。

Number

数字类型,有最大值(Number.MAX_VALUE)和最小值(Number.MIN_VALUE)限制,超出后会自动转换为特殊值 InfinityNaN(非数值,Not-a-Number)

Undefined

只有一个值 undefined,JavaScript中,一个没有被赋值的变量会有个默认值 undefined

Symbol

符号类型,是ES6中新定义的原始数据类型,符号类型是唯一的并且不可修改不可枚举

  • 作为Object属性key可以保证永远不会出现同名属性,防止属性污染
  • 模拟class私有属性,控制变量读写
const garen = Symbol(); // 盖伦标记
const jarvanIV = Symbol(); // 嘉文四世标记
// 德玛西亚类
class demacia {
  constructor(){
    this[garen] = 'Garen';
    this[jarvanIV] = 'JarvanIV';
  }
  getGaren(){
    return this[garen];
  }
  setGaren(value){
    this[garen] = value;
  }
  getJarvanIV(){
    return this[jarvanIV];
  }
  setJarvanIV(value){
    this[jarvanIV] = value;
  }
}
复制代码

Bigint

字如其意,ES11新增加的数据类型类型,可以通过在整数末尾附加 n 创建,BigInt可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。

复杂数据类型

  • Null
  • Object
  • Function

Null

Null类型只有一个值 nulltypeof null 值为 object

Object

对象类型,几乎所有可以通过 new Keyword 创建的,类型都是 Object,例如 new Array()new Date()new Map()new Set()new WeekMap(), new WeekSet() 等。

Function

Function 是一个特殊的 ObejctFunction 的原型对象 prototype 的原型 __proto__ 指向 Object(有点绕口,关于原型对象和原型,在后续说到原型编程时会讲)

Array

数组类型,常用于表示列表数据
数组的方法可总结为三类

  • 会改变调用它们的对象自身的值,poppushreversesplice
  • 不会改变调用它们的对象的值,只会返回一个新的数组,concatslicejoin
  • 遍历方法,遍历过程中,不要对原数组进行任何操作,否则遍历结果可能会受影响,foEachentrieseverysomefilterfind

不同方法的具体用法这里就不一一说明了。

参考资料【MDN】数组Array

Date

日期类型,基于 Unix Time,即自 1970年1月1日(UTC) 起经过的 毫秒数

Set,WeakSet,Map,WeakMap

  • Map:键值对,并且能够记住键的原始插入顺序。任何值都可以作为一个键或一个值
  • WeakMap:键必须是对象,而值可以是任意的,不可枚举,键名所指向的对象,都是弱引用,不计入垃圾回收机制
  • Set:任意值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是唯一的。
  • WeakSet:对象值的集合,不可枚举,对象都是弱引用,不计入垃圾回收机制

不同数据类型的储存

JavaScript的 堆栈和 Java 有些许差别

  • 栈:原始类型的局部变量,对象的引用
  • 堆:原始类型的全局变量,闭包场景中的变量, 对象类型数据

解释:下图中 闭包函数原始类型变量b 还存在于[[Scopes]]对象中

var a = 1;
var f1 = function() {
  var b = 2;
  return function(){ console.log(b) }
}
console.dir(f1())
复制代码

image.png

类型判断

typeof

检测一个变量的类型

typeof '1' // string

typeof 1 // number

typeof 1n // bigint

typeof false // boolean

typeof undefined // undefined

typeof null // object

typeof [] // object

typeof new Date() // object

typeof function(){} // function

typeof Date // function

typeof Array // function
复制代码

typeof null 的值为 object

这是个历史遗留的 Bug,娘胎里带出来的

不同的对象在底层都表示为二进制,在JavacSript二进制前三位都为0的话会被判断为是Objectnull 的二进制表示全为0,自然前三位也是0,所以执行 typeof 时会返回 object
判断 null 类型,建议用 xxx=== null
对于复杂类型的数据来说,函数的类型为 function,对象的类型为 object

instanceof

返回true/false,用于检测构造函数的 prototype 是否出现在实例对象的 原型链 上,从而判断对象类型。

如何手动实现 instanceof

instanceof 可以正确的判断对象的类型,原理是通过判断对象的原型链中能不能找到对应的类型。

function instanceof(left, right) {
  // 原型
  let proto = left.__proto__;
  // 一层一层找对应的原型对象
  while(proto) {
    if (proto === right.prototype) {
      return true;
    }
    proto = proto.__proto__
  }
  return false;
}
复制代码

Object.prototype.toString

个人比较推荐的判断类型的方法是Object.prototype.toString,可以完整的判断数据的类型,需要搭配 call 或者 apply 使用

Object.prototype.toString.call('1') // [object String]

Object.prototype.toString.call(1) // [object Number]

Object.prototype.toString.call(1n) // [object BigInt]

Object.prototype.toString.call(false) // [object Boolean]

Object.prototype.toString.call(undefined) // [object Undefined]

Object.prototype.toString.call(null) // [object Null]

Object.prototype.toString.call({}) // [object Object]

Object.prototype.toString.call([]) // [object Array]

Object.prototype.toString.call(new Date()) // [object Date]
复制代码

返回值[object {type}] 中的 type 就是变量的类型

类型转换

  • 强制转换
  • 隐式转换

强制转换

通过 String(),Number(),Boolean()等函数做类型转换

隐式转换

类型转换中,编译器自动转换的方式,通常发生在通过运算符运算时

  • 算术运算符 +-*÷%
  • ==!=
  • 条件运算 if( )else if( )

算术运算符

  • 字符串 + 数字,数字会转成字符串
  • 数字 - 字符串,字符串会转成数字。如果字符串不是纯数字就会转成NaN。字符串-数字也一样。字符串-字符串也要先转成数字
  • +*÷%><- 的转换也是一样

==,!=

先自动做类型转换,再比较

  • 字符串和数字比时,会将字符串转为数字,再比较
  • 字符串和布尔比时,都转为数字,再比较
  • 数字和布尔比时,会将布尔转为数字,再比较

条件运算

将条件内数据或表达式转换为 Boolean

转换例子

转Number

  • true 为 1,false 为 0
  • null 为 0,undefinedNaNsymbol 报错
  • 字符串看内容,如果是数字或者进制值就正常转,否则就 NaN
Number(true) // 1
Number(false) // 0
Number(null) // 0
Number(undefined) // NaN
Number(Symbol('1')) // Uncaught TypeError: Cannot convert a Symbol value to a number at Number
Number('1')  // 1
Number('1a') // NaN
parseInt('1') // 1
parseInt('1.23 abc') // 1
parseFloat('1.1') // 1.2
parseFloat('1.1 abc') // 1.1
+'1'  // 1
复制代码

转String

String(1) // '1'
1.toString() // '1'
1.234.toFixed('2') // '1.23'
复制代码

转Boolean

  • undefinednullfalse0-0NaN空字符串 转为 false
  • 其他所有值都转为 true
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean('') // false
Boolean('0') // true
Boolean(NaN) // false
Boolean({ a: null }) // `true`
复制代码

相等性判断

  • 非严格相等比较 (==)
  • 严格相等比较 (===)
  • Object.is(args1,args2)

区别

  • ==将执行类型转换后,比较值
  • ===直接进行相同的比较,而不进行类型转换 (如果类型不同, 总会返回 false )
  • Object.is=== 处理类似,但是对NaN0-0进行特殊处理,Object.is(NaN,NaN)结果为trueObject.is(0. -0) 结果为 false

参考资料

最后

三人行,必有我师焉
掘金不停,代码不止
互相学习,共同进步

文中如有错误,欢迎在评论区指正。
如果这篇文章对你有所帮助,欢迎点赞、评论和关注。

系列文章

  • 【FuckingJavaScript系列】数据类型,你真的掌握了吗?
  • 【FuckingJavaScript系列】原型编程,你真的理解了吗?
  • 【FuckingJavaScript系列】函数编程,你真的熟练了吗?
  • 【FuckingJavaScript系列】异步编程,你真的学会了吗?
  • 【FuckingJavaScript系列】事件循环,你真的明白了吗?
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享