JavaScript数据类型笔记
数据类型是JavaScript 编程语言的基础知识 有 空(Null)未定义(Undefined)字符(String)数字(Number)布尔值(Boolean)符号(Symbol)对象(Object)
数据类型分
基础类型 空(Null)未定义(Undefined)字符(String)数字(Number)布尔值(Boolean)符号(Symbol)
引用类型 对象(Object)
基础类型是值传递,新声明的变量等值传递了原来的变量,属于深拷贝
引用类型是声明的变量只是引用了原有对象创建的指针,两个变量其实是共享一个对象。属于浅拷贝
Undefined
只有一个值 就是undefined
声明变量未定义值
引用的函数没有返回值
引用的对象属性没有值
void 0 为 undefined
全局常量 window.undefined
var a //
var b= function(){} //
var c = {} //
c.d //
void 0
window.undefined
判断一个变量值是否为undefined
c === undefined
// Uncaught ReferenceError: c is not defined
typeof v === undefined
//false
typeof b === 'undefined'
//false
var g
typeof g === 'undefined'
//true
typeof g
//"undefined"
Null
Null 数据类型和 Undefined 类似,只有唯一的一个值 null,都可以表示空值,甚至我们通过 “==” 来比较它们是否相等的时候得到的结果都是 true,但 null 是 JavaScript 保留关键字,而 undefined 只是一个常量。
也就是说我们可以声明名称为 undefined 的变量(虽然只能在老版本的 IE 浏览器中给它重新赋值),但将 null 作为变量使用时则会报错。
Boolean
布尔值 有两个 true 和 false 做判断时候 数据类型会被强制转换
0 undefined null 空字符串 都会被转化为false
Number
数值类型有两个特殊的值
NaN(not a number) 不是数值的值
NaN(Not a Number)通常在计算失败的时候会得到该值。要判断一个变量是否为 NaN,则可以通过 isNaN 函数进行判断。
isNaN('sadasd')
//true
isNaN('123')
//false
isNaN(123)
//false
Infinity 是无穷大,加上负号 “-” 会变成无穷小,在某些场景下比较有用,比如通过数值来表示权重或者优先级,Infinity 可以表示最高优先级或最大权重。
对于数字类型的浮点计算还要注意精度的问题 0.1+0.2 没有得到0.3
0.1+0.2
//0.30000000000000004
因为在数值计算时JavaScript 引擎会先将十进制数转换为二进制,然后进行加法运算,再将所得结果转换为十进制。在进制转换过程中如果小数位是无限的,就会出现误差。同样的
十进制转化为二进制计算,计算中小数位是无限的容易出现误差
解决方案
小数位不多的比如金额计算 换算为整数计算再除以对应百单位比
(0.1*100 + 0.2*100)/100
//0.3
小数位多的 截取12位 再用浮点方法转化
parseFloat((0.1 + 0.2).toPrecision(12)) // 0.3
String
字符类型拥有多种API方法
千位分隔符
function sep(n) {
let [i, c] = n.toString().split(/(\.\d+)/)
return i.split('').reverse().map((c, idx) => (idx+1) % 3 === 0 ? ',' + c: c).reverse().join('').replace(/^,/, '') + c
}
function sep2(n){
let str = n.toString()
str.indexOf('.') < 0 ? str+= '.' : void 0
return str.replace(/(\d)(?=(\d{3})+\.)/g, '$1,').replace(/\.$/, '')
}
Symbol
Symbol 是 ES6 中引入的新数据类型,它表示一个唯一的常量,通过 Symbol 函数来创建对应的数据类型,创建时可以添加变量描述,该变量描述在传入时会被强行转换成字符串进行存储。
var a = Symbol('1')
var b = Symbol(1)
a.description === b.description // true
var c = Symbol({id: 1})
c.description // [object Object]
var _a = Symbol('1')
_a == a // false
基于上面的特性,Symbol 属性类型比较适合用于两类场景中:常量值和对象属性。
避免常量值重复
如果代码中使用了魔术字符串(魔术字符串是指在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值),导致调用 getValue 函数时需要查看函数源码才能找到参数 key 的可选值。所以可以将参数 key 的值以常量的方式声明出来。在这种场景下更适合使用 Symbol,我们不关心值本身,只关心值的唯一性
const KEY = {
alibaba: Symbol(),
baidu: Symbol(),
bytedance: Symbol()
}
function getValue(key) {
switch(key){
case KEY.alibaba:
// do something
console.log('alibaba')
break;
case KEY.baidu:
console.log('baidu')
break;
}
}
getValue(KEY.baidu);
//baidu
避免对象属性覆盖
假设有这样一个函数 fn,需要对传入的对象参数添加一个临时属性 user,但可能该对象参数中已经有这个属性了,如果直接赋值就会覆盖之前的值。此时就可以使用 Symbol 来避免这个问题。
创建一个 Symbol 数据类型的变量,然后将该变量作为对象参数的属性进行赋值和读取,这样就能避免覆盖的情况,示例代码如下:
function fn(o) { // {user: {id: xx, name: yy}}
const s = Symbol()
o[s] = 'zzz'
console.log(o[s])
o[s] = {user: {id: 'xx', name: 'yy'}}
console.log(o[s])
}
fn({age:12})
//zzz
//{user: {…}}
类型转换
JavaScript 这种弱类型的语言,相对于其他高级语言有一个特点,那就是在处理不同数据类型运算或逻辑操作时会强制转换成同一数据类型。如果我们不理解这个特点,就很容易在编写代码时产生 bug。
通常强制转换的目标数据类型为 String、Number、Boolean 这三种。下面的表格中显示了 6 种基础数据类型转换关系。
String | Number | Boolean | |
Undefined | 'undefined' | NaN | false |
Null | 'null' | 0 | false |
String | - | 对应的数值或者NaN | 除了空值以外都为true |
Number | 对应的字符串 | - | 除了0以外都为true |
Boolean | 'true' 或者 'false' | 1 或者 0 | - |
Symbol | 不可转换 | 不可转换 | true |
除了不同类型的转换之外,操作同种数据类型也会发生转换。把基本类型的数据换成对应的对象过程称之为“装箱转换”,反过来,把数据对象转换为基本类型的过程称之为“拆箱转换”。
对于装箱和拆箱转换操作,我们既可以显示地手动实现,比如将 Number 数据类型转换成 Number 对象;也可以通过一些操作触发浏览器显式地自动转换,比如将对 Number 对象进行加法运算。
var n = 1
var o = new Number(n) // 显式装箱
o.valueOf() // 显式拆箱
n.toPrecision(3) // 隐式装箱, 实际操作:var tmp = new Number(n);tmp.toPrecision(3);tmp = null;
o + 2 // 隐式拆箱,实际操作:var tmp = o.valueOf();tmp + 2;tmp = null;
什么时候会触发类型转换?
下面这些常见的操作会触发隐式地类型转换,我们在编写代码的时候一定要注意。
- 运算相关的操作符包括 +、-、+=、++、* 、/、%、<<、& 等。
- 数据比较相关的操作符包括 >、<、== 、<=、>=、===。
- 逻辑判断相关的操作符包括 &&、!、||、三目运算符。
Object
引用类型 以键值对方式展现,可以层级嵌套
object类型数据是键值对的集合
键:字符串、symbol
值:任意类型的值
子类型有 Date Array Set RegExp