为什么要区分数据类型?
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位浮点来存储数字的,没有单独的整数。
- 虽然0、正0、负0都等于0,但正0和负0是不一样的。
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 == 2、1 !== 2、3 === 4、3 !== 4 - 比较运算:
1 > 2、1 >= 2、3 < 4、3 <= 4
五个falsy值
- falsy:相当于是false,但又不是false的值。
- 五个falsy值
0NaN''undefinednull
- 注意
'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 = 1const 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).toString、1..toString不会报错。
- JS中
转换为Booelan
Boolean(数据)- 例:
let a = 10 console.log(Boolean(age)) // true
拓展
浮点数为什么不精确?
- 计算机中对于小数采取“乘2取整,顺序排列”的方法来转化为二进制,具体做法是:
- 用2乘十进制小数,可以得到积。
- 将积的整数部分取出,再用2乘余下的小数部分,又得到一个积。
- 如此进行,直到积中的小数部分为零。
- 经过实践可以发现,除非算到最后小数末尾为恰好为5,不然这种算法会一直持续下去,出现无限小数。
- 这就迫使计算机不得不采取取近似值的方式来表示小数。
对象的属性
- 只有Object才有属性。
- String、Boolean、Number理应是没有属性一说的。
- String有属性是历史原因。
var声明存在的问题
- 可以先使用,再声明(不合理)。
- var声明过的变量可以重复声明(不合理)。
- 其他问题:变量提升、全局变量、没有块级作用域等等。
简单数据类型和复杂数据类型
- 简单数据类型:Number、Boolean、undefined、null、Symbol、String
- 复杂数据类型:Object