JS数据类型分析

238 阅读6分钟

数据为什么需要类型?

我们拿数字1与字符串'1'做对比;都是一,为什么要区分1与''1';
功能不同

  • 数字能加减乘除,字符串不能
  • 字符串能表示电话号码,数字不行

储存形式不同

  • 在JS中,数字是使用64位浮点数的形式储存
  • 字符串是使用类似UTF8形式储存的(UCS-2)

数据类型

js基本数据类型可分为7类:

  • 数字number
  • 字符串string
  • 布尔 bool
  • 符号 symbol
  • 空 undefined
  • 空 null
  • 对象 object
    使用一句话总结:四基二空一对象;特别注意数组、函数、日期不是数据类型,都属于object

数字类型

js的存储形式是64位浮点数,浮点就是浮动的点,意思是小数点会乱动;

  • 123.456可以表示为1.23456e10^2,也可以表示为123456e10^-3
  • 数字占64位内存,其中符号占1位,指数占11位(其中指数符号占1位,数字占10位,所以指数换成10进制范围为-1024~1024),有效数字占52位(开头的1省络);

数字的写法

  • 整数:1
  • 小数:0.2
  • 科学计数法: 1.23e4 (相当于12300)
  • 八进制:00123
  • 十六进制: 0X3F
  • 二进制: 0b11

特殊的值

  • +0,-0都等于0
  • 无穷大:infinity,+infinity,-infinity
  • NaN:无法表示的数字

** 精度(有效数字)**

  • 最多只有53个二进制表示有效数字,对应的十进制是9后面15个0;
  • 所以15位数字都能精确表示
  • 16位有效数字如果小于9开头,也能精确表示,大于9的话就不能精确表示

字符串类型

字符串的存储是每个字符2个字节,是使用的阉割版的UTF-8; 写法

  • 单引号 'hello'
  • 双引号 "hello"
  • 反引号 hello

** 转义 ** 当我们表达'it's ok'时,js引擎会it'结束了,后面的就看不懂了,这时就需要转义符了\

正确的写法

  • 'it\'s ok' 单引号
  • "it's ok" 双引号
  • it's ok 反引号方式 转义
  • ' 表示'
  • " 表示"
  • \n 表示换行
  • \r 表示回车
  • \t 表示tab制表符
  • \ 表示\
  • \uFFFFB表示相对于的unicode字符码

布尔

布尔只有两个值,true后者false
有以下方式可以得到布尔值

  • 否定运算 !value
  • 相等运算符 1==2;1===2; 1 != 2; 1 !==2;
  • 比较运算符 1>2;1>=2;1<2;1<=2
  • 5个falsy值,相当于false,但是又不是false;undefined、null、0、NaN、''

null undefined

这是两种空类型;

  • 两者没有本质的区别
  • 区别细节一:如果声明了一个变量,但是没有赋值,则默认的值为undefined
  • 区别细节二:如果一个函数,里面没有return,则默认返回值为undefined

对象

对象是唯一的一个复杂数据类型,上面介绍的6种数据类型都是基本数据类型

定义

无序的数据集合,也叫做键值对的集合

写法

let obj = { 'name': 'alice', 'age': 20}

细节说明

  • 键名是字符串,不是标识符,也就是没有限制规则,可以使用任何字符,但是前提是要使用引号;
  • 虽然引号可以省络,但是省咯后只能写标识符,意思是要使用标识符的表示规则;
  • 就算是引号省络了,键名也还是字符串,因为属性名会自动变成字符串;

上面中键名发生了变化,因为我们如果不加引号,js会先把键名转换成了字符串,再转换的过程就发生了变化

如果我们不希望键名不发生就变化,可以使用引号引起来

上面我们都是使用的常量作为属性名字,除了使用常量,我们还可以使用变量,但是要把变量名称放到[]里面

let name = 'haha'
let obj = { [name]: 'alice', 'age': 20}

不加[]的属性名会自动变成字符串,加了[]会当做变量求值

对象的隐藏属性

  • js中每个对象都有一个隐藏属性;
  • 这个隐藏属性存储着其共有属性组成的对象的地址;
  • 这个共有属性组成的对象叫原型;
  • 也就是隐藏属性存储着原型的地址;
  • 此原型包含了所有对象的共有属性,是对象的根;
  • 对象的原型也是对象,因此对象的原型的原型是null

那这隐藏对象有什么用途呢

这隐藏对象指向的原型可以给每个js实例对象提供共有的属性与方法,这样每个实例对象不需要自己去定义,就可以使用已定义好的属性与方法;

查看所有对象属性

  1. 查看自身所有属性,使用Object.key(obj)
let obj = { 'name': 'alice', 'age': 20};
Object.keys(obj);

2. 查看自身与共有属性,可使用console.dir(obj)
3. 判断一个属性是自身的还是共有的obj.hasOwnProperty(key)

4. 查看属性的值,有两种方法,一种是[]方法,obj['key'],如果key为变量,要把引号去掉obj[key];另外一种方法是:点语法obj.key;优先使用[]方法

修改增加属性

  • 直接赋值
let obj = {}
obj.name = 'alice';
obj['age'] = '22';
let haha = 'sex';
obj[haha] = 'baomi'
// {name: "alice", age: "22", sex: "baomi"}
  • 批量赋值
Object.assign(obj,{rabit:'haha', color: 'black'})
// {name: "alice", age: "22", sex: "baomi", rabit: "haha", color: "black"}
  • 修改共有属性
    原则上无法通过自身增加或者修改共有属性

如果你一定要修改或者共有属性,也是有方法的,以下有两种方式,但是建议第二种

  1. 通过修改实例对象上面的共有属性__proto__所对应的原型上面的属性,但是不建议使用这种方法

2. 直接修改对象的原型对象上面的属性Object.prototype

以上不管通过哪种方式,都尽量不要修改共有属性,所以可以看出js本身比较脆弱,共有属性竟然能够被修改

  • 修改隐藏属性
  1. 直接修改__proto__,请注意不会更改其他对象的原型

2. 在新创建对象的时候就修改原型

通过上面,是不是可以看到很有意思的现象,虽然我们更改了obj4的__proto__,变成了common对象的地址,但是common本身又是对象,它的__proto__又指向了共有的原型,这就是原型链,所以obj4同样也可以使用toString方法

删除属性

  • 使用delete obj['key'] 即可,返回值为布尔值

结束语

此文章记录了自己在饥人谷学习成果,感谢方方老师;