【JS全解】JS数据类型

172 阅读9分钟

为什么要区分数据类型?

  • 1 !== '1'
  • 不同数字类型的功能不同。
    • 数字能加减乘除,字符串不行。
    • 字符串能存储电话号码,数字不行。
  • 不同数字类型的存储形式不同。
    • JS中,数字是以64位浮点数的形式存储的。
    • JS中,字符串是以类UTF-8形式存储的(UCS-2)。
  • 计算机本身并不能分辨字符串和数字,要靠给它的文件格式(数据类型)来辨别。

二进制

  • 数据在计算机中是以二进制存储的。
  • 符号为B(BINS)。
  • 二进制转十进制
    • 除2取余,逆序排列。
  • 十进制转二进制
    • 乘2取整,顺序排列。
  • 一个二进制数在计算机中为“1位”

十六进制

  • 符号为H(HEX)。
  • 十六进制:123456789ABCDEF
  • 为什么用十六进制?
    • 因为二进制写起来太慢了。
  • 二进制转十六进制
    • 从右往左每四位二进制改写为一位十六进制。
    • 011110001011010(B)→3C5A(H)
  • 一个十六进制在计算机中为“1字节”,即“1字节=4位”。

字符编码

ASCII码

  • 用0~127表示键盘上所有符号。
  • 所有编码的前128位都和ASCII码一致。
  • 0用48表示。
  • A用65表示。
  • a用97表示。

GB2312

  • 国标2312,用来表示中文字符。
  • 用2字节表示一个字,0000~FFFF最多可以存储65k个字符。
  • GB2312只收录了6000多汉字、西文字母、日文假名。
  • 没有收录生僻字、繁体字、韩文等。

GBK

  • 国标扩,微软推出的汉字标准。
  • 依然使用2字节表示一个字。
  • 收录了20k个汉字和图形符号,几乎囊括了中日韩所有汉字。
  • 完全兼容GB2312。

Unicode

  • 一次性解决所有文字需求的“万国码”。
  • 已经收录130k字符,还能继续扩充。
  • 每个字符要用3个及以上字节。
  • 为了解决字符占用字节增多可能带来的文件体积变大的问题,UTF-8诞生了。
  • 通过在字符前添加代表字节数的数字,UTF-8用1字节来存储英文字母(比GBK还省),用3字节来存储中文(和GBK一致)。
  • UTF-8中8的意思是:最少可用8位存一个字符。
  • UTF-8是Unicode的一种存储规则,也叫字符编码规则。

JS中的数据类型

  • 八种数据类型
    • Number
    • String
    • Boolean
    • Symbol(符号)
    • undefined
    • null
    • Object
    • Bigint(新增)
  • 数组、函数、日期都不属于数据类型,他们都是一种特殊的Object。

number

  • 整数:1
  • 小数:0.1
  • 科学计数法:1.23e4
  • 八进制:00123
    • 0、00、0o开头
  • 十六进制:0x3F
    • 0x、0X开头
  • 二进制:0b11
    • 0b开头,0B开头
  • 注意
    • 虽然0、正0、负0都等于0,但正0和负0是不一样的。
      1 / 0 // Infinity
      1 / +0 // Infinity
      1 / - 0 // -Infinity
      
    • 无穷大:Infinity、+Infinity、-Infinity
    • NaN,Not a Number,无法表示的数字,但这是一个数字。
       0 / 0 // NaN
       NaN === NaN // false
      
    • NaN不等于另一个NaN。
    • JS是以64位浮点来存储数字的,没有单独的整数

64位浮点

  • 浮点就是浮动的点,即小数点是会乱动的。如123.456既可以表示为1.23456e10^2,也可以表示为12345.6e10^-2。
  • 把数字转化为二进制后,通过浮点,小数的第一位可以永远表示为1。
  • JS中
    • 符号占1位
    • 指数占11位(-1023~1024)
    • 有效数字占52位(省略开头的1)

范围和精度

  • 范围(忽略符号位)
    • 指数拉满、有效数字拉满,得到最大二进制数字:
      • Number.MAX_VALUE: 1.7976931348623157e+308
    • 指数负方向拉满、有效数字最小1,得到最小二进制数字:
      • Number.MIN_VALUE: 5e-324
    • 范围:1*10^300~1*10^-300
  • 精度(有效数字)
    • 最多只能到52+1个二进制位表示有效数字。
    • 2^53对应的十进制是9后面15个零。
    • 所以15位有效数字都能精确表示。
    • 16位有效数字如果小于90开头,也能精确表示。
    • 9110000000000001就存不下来。
    • 精度:15位数

string

  • 单引号:'你好'
  • 双引号:"你好"
  • 反引号:`你好`
  • 注意
    • 引号不属于字符串的一部分,就像书名号不属于书名的一部分一样。
    • 怎么在引号里加引号?
      • 转义符\'我说\'你好\''
      • 单引号双引号交替使用:'我说"你好"'

转义

  • 用另一种写法表示你想要的东西
  • \'表示'
  • \" 表示"
  • \\ 表示\
  • \uFFFF表示对应的Unicode字符
  • \xFF表示前256个Unicode字符

多行字符串

  • 在反引号里可以直接用回车来对字符串分行。
    let s = `
    	hello
    	world
    `
    

字符串的属性

  • String.length
    • 用来表示字符串的长度。
    • '123'.length // 3
    • '\n\r\t'.length // 3
    • ''.length // 0
    • ' '.length // 1
    • 注意
      • 转义符\是不计入字符串长度的。
      • 空字符串和空格字符串是不同的。
  • String[index]
    let str = "abcdef"
    str[0] // a
    str[6] // undefined
    
    • 可以像Array一样,用index来检索字符串中对应字符。

base64转码

window.btoa('123') // 'MTIz'
window.atob('MTIz') // '123'
  • window.btoa(String)
    • 编码。正常字符串转为Base64编码的字符串。
  • window.atob(String)
    • 反编码。Base64编码的字符串转为原来的字符串。

boolean

  • 布尔只有两个值:true、false
  • 以下运算都能得到布尔值
    • 否定运算:!value
    • 相等预算:1 == 21 !== 23 === 43 !== 4
    • 比较运算:1 > 21 >= 23 < 43 <= 4

五个falsy值

  • falsy:相当于是false,但又不是false的值。
  • 五个falsy值
    • 0
    • NaN
    • ''
    • undefined
    • null
  • 注意
    • '0'是字符串,所以是真。

undefined和null

  • undefined和null没有本质区别。
  • 如果一个变量声明了,但没有赋值,那么默认值就是undefined。
  • 如果一个函数,没有写return,那么默认return undefined。
  • 习惯上,把非object的空值写为undefined,把object的空值写为null。

Symbol

  • Symbol 生成一个全局唯一的值,让他有别与其他同样调用了Symbol()的属性。
var group = {
  a: Symbol(),
  b: Symbol(),
  c: Symbol()
}

group.a !== group.b // true
group.a !== group.c // true
  • 也可以给Symbol起名,但这个名字和Symbol的值没有关系。
var group = {
  a: Symbol('name'),
  b: Symbol('name'),
  c: Symbol('name')
}

group.a !== group.b // true
group.a !== group.c // true

变量声明

  • 三种声明方式
    • var a = 1不推荐
    • let a = 1
    • const a = 1
  • 区别
    • var是过时的、不好用的方式。
    • let是新的,更合理的方式。
    • const是声明时必须赋值,且不能再改的方式。用于常量的声明
  • 变量声明在指定了值的同时也指定了数据类型。
    • let a = 1,既指定了a为1,也指定了a为number类型数据。
    • JS为弱数据类型,已声明的变量的值和类型都可以随意变化,例:a = '字符串'

let规则

  • 遵循块作用域,即使用范围不能超出{}
  • 不能重复声明。
  • 可以赋值,也可以不赋值。但必须先声明再使用,如下代码会报错:
    console.log(a);
    let a = 1;
    
  • 全局声明的let变量,不会变成window的属性。
    var a = 1;
    window.a; // 1
    let b = 2;
    window.b // undefined
    
  • for循环配合let有[[3. JS语法#for循环下的setTimeout|奇效]]。

const规则

  • 跟let几乎一样。
  • 区别:声明时就要赋值,赋值后不能改。
  • 一般用于声明常量。

类型转换

隐式转换

  • +号两边只要有一个是字符串,都会把另外一个转成字符串。
  • 除了+以外的算术运算符(如-、*、/ 等)都会把数据转成数字类型。
  • 例:
    console.log(11 + '11') // 1111
    console.log(11 - '10') // 1
    console.log(11 * '10') // 110
    

隐式转换中转换为Number

  • 使用+
    let a = '1';
    + a //1
    
    • 这里的第二个+号并不代表“加号”,而是作为“正负”中的“正号”
  • 使用-
    let a = '1';
    a - 0 // 1
    
    • -号会把字符串转成数字再减0。

隐式转换中转换为String

let a = 1;
a + '' // '1'

隐式转换中转换为Boolean值

let a = 10;
console.log(!!a) // true

显式转换

  • 概念: 自己写代码告诉系统该转成什么类型

转换为Number

  • Number(数据)
    • 转成数字类型。
    • 如果字符串内容里有非数字,转换失败,结果为 NaN。
      • 如:console.log(Number('abc')) // NaN
  • parseInt(数据)
    • 只保留整数。
    • 这里本质上还是一个小数,因为JS中只有64位浮点的数字存储方式。
  • parseFloat(数据)
    • 可以保留小数。
    • 如果是以数字开头,字符串里可以存在非数字,会自动过滤非数字以及之后的内容。这种特性常用于过滤单位,例:console.log(parseFloat('123.1元')) // 123.1
    • 例:
      console.log(parseFloat('123.1abc')) // 123.1
      console.log(parseFloat('abc123.1')) // NaN
      console.log(parseFloat('123.1abc123')) // 123.1
      

转换为String

  • String(数据)
  • 变量.toString(进制)
    • 例:
      let age = 10
      console.log(age.toString(2)) // 1010
      
  • 注意
    • JS中console.log(String(1000000000000000000000)) // '1e+21',21个0之后,会显示成科学计数法。
    • 1.toString会报错,但(1).toString1..toString不会报错。

转换为Booelan

  • Boolean(数据)
  • 例:
    let a = 10
    console.log(Boolean(age)) // true
    

拓展

浮点数为什么不精确?

  • 计算机中对于小数采取“乘2取整,顺序排列”的方法来转化为二进制,具体做法是:
    1. 用2乘十进制小数,可以得到积。
    2. 将积的整数部分取出,再用2乘余下的小数部分,又得到一个积。
    3. 如此进行,直到积中的小数部分为零。
  • 经过实践可以发现,除非算到最后小数末尾为恰好为5,不然这种算法会一直持续下去,出现无限小数。
  • 这就迫使计算机不得不采取取近似值的方式来表示小数。

对象的属性

  • 只有Object才有属性。
  • String、Boolean、Number理应是没有属性一说的。
  • String有属性是历史原因。

var声明存在的问题

  • 可以先使用,再声明(不合理)。
  • var声明过的变量可以重复声明(不合理)。
  • 其他问题:变量提升、全局变量、没有块级作用域等等。

简单数据类型和复杂数据类型

  • 简单数据类型:Number、Boolean、undefined、null、Symbol、String
  • 复杂数据类型:Object