1.JS数据类型有哪些?
一共8种, 来个口诀(五基两空一对象)
解释一下
五基:
- number
- boolean
- string
- bigInt
- symble
两空:
- null
- undefined
一对象:
- object
其中五基+两空属于原始数据类型,而Object属于引用数据类型,Object中还包括(普通对象Object, 数组对象Array, 正则对象-RegExp, 日期对象-Date,数学函数Math, 函数对象Function)
2.那些属于原始数据类型?
2.1 数字--Number
写法
- 整数写法--1
- 小数写法--0.1
- 科学计数法
- 1.23e4
- 八进制写法(0123或00123或0o123)
- 十六进制写法(0x3F或0X3F)
- 二进制写法(0b11或0B11)
特殊值
- 正0和负0都等于0,但是当+0/infinity 结果是infinity 当-0/infinity 结果是 -infinity
- NaN--无法表示的数字
数字的范围
Number.MAX_VALUE ~ Number.MIN_VALUE
数字的精度
15位有效数字都能精确表示
16位有效数字如果小于90开头,也能精确表示 举个栗子
console.log(1111111111111111) // 1111111111111111 15位时准确
console.log(11111111111111111) // 1111111111111112 16位时失准
延伸面试题 0.1 + 0.2 为什么不等于0.3? 标准答案👇
0.1和0.2在转换成二进制后会无限循环,由于标准位数的限制后面多余的位数会被截掉,此时就已经出现了精度的损失,相加后因浮点数小数位的限制而截断的二进制数字在转换为十进制就会变成0.30000000000000004。
推荐博客: 0.1 + 0.2不等于0.3?为什么JavaScript有这种“骚”操作?
2.2 字符串--String
写法
- 单引号 '你好'
- 双引号 “你好”
- 反引号
你好
注意:引号不属于字符串的一部分
如果想要在单引号中包含单引号:
转义
用另一种写法表示你想要的东西、
序 | 转义字符 | 使用说明 |
---|---|---|
0 | NUL字符(\u0000) | |
1 | \b | 后退一格(Backspace)退格符(\u0008) |
2 | \f | 换页(Form Feed)(\u000C) |
3 | \n | 回车(Carriage Return)(\u000D) |
4 | \r | 回车(Carriage Return)(\u000D) |
5 | \t | 制表(Tab)水平制表符(\u0009) |
6 | ' | 单引号(\u0027) |
7 | " | 双引号(\u0022) |
8 | \ | 反斜线(Backslash)(\u005C) |
9 | \v | 垂直制表符(\u000B) |
10 | \xNN | 由两位十六进制数值NN指定的Latin-1字符 |
11 | \uNNNN | 由四位十六进制数NNNN指定的Unicode字符 |
12 | \NNN | 由一位到三位八进制数(1到337)指定的Latin-1字符。ECMAScript v3不支持,不要使用这种转义序列 |
多行字符串
这里就不介绍双引号包裹的情况,直接推荐模板字符串。 举个栗子👇 let s = (反引号)这样是 可以的 用反引号很容易做到(反引号)
反引号指的是`
以前没有反引号的时候很麻烦,详情请参考:网道教程。
常用Api
字符串数据类型常用的Api包括 String.prototype.length 返回字符串的长度 String.prototype.charAt() 返回特定位置的字符 String.prototype.concat() 连接两个字符串文本 String.prototype.padStart() 在当前字符串前面填充指定的字符串,直到达到指定长度,返回一个新的字符串 String.prototype.slice() 摘取一个字符串区域,返回一个新的字符串 String.prototype.substring() 返回在字符串中指定两个下标之间的字符 String.prototype.split() 通过分离字符串成字串,将字符串对象分割成字符串数组 这里只列举一些我平时比较常用的。
延伸 为什么字符串会有属性? 再具体一点,为什么"a".toString()可以被调用? 答案:基本包装类型,在这个语句执行过程中会做这样几件事
var s = new Object("a")
s.toString()
s = null
第一步: 创建Object类实例。注意为什么不是String ? 由于Symbol和BigInt的出现,对它们调用new都会报错,目前ES6规范也不建议用new来创建基本类型的包装类。
第二步: 调用实例方法。
第三步: 执行完方法立即销毁这个实例。
整个过程体现了基本包装类型
的性质,而基本包装类型恰恰属于基本数据类型,包括Boolean, Number和String。
参考:《JavaScript高级程序设计(第三版)》P118
2.3 布尔值--Boolean
定义
Boolean只有两个值true和false
下列运算符会得到bool值 否定运算 !value 相等运算 1==2, 1!=2,3===4,3!==4 比较运算 1>2,1>=2,3<4
真值
在 JavaScript 中,truthy(真值)指的是在布尔值上下文中,转换后的值为真的值。所有值都是真值,除非它们被定义为 假值(即除 false
、0
、""
、null
、undefined
和 NaN
以外皆为真值)。(参考自MDN)
2.4 类型转换
JS中,类型转换只有三种
- 转换为数字
- 转换为布尔值
- 转换为字符串
转换规则具体如下
注意"Boolean 转字符串"这行结果指的是 true 转字符串的例子
2.5 Symbol
定义
与前面几种原始数据类型不同的是,Symbol是ES6中新增的原始数据类型,表示独一无二的值。
应用场景 一般用于防止属性名冲突。 设想一个场景
春娇是个女程序媛,她写了一个可以帮助大家记账的小工具,但是里面只有简单的加减乘除算法。
志明是春娇的同事,他觉得这个小工具很好用,但是有点缺陷,就是没有根号运算,于是他打算向里面添加一个函数用来进行根号运算。可是怎么起函数名呢?会不会与之前的函数名冲突呢?这让他犯了难。于是他不得不去找春娇询问,这一来二去,天长地久,他们....., 呸,不好意思,走偏了。
可以发现以字符串来对属性名命名是有缺陷的,无法保证属性名唯一。 这也是Symbol出现的原因。
用法 1.最基本的用法
let s = Symbol();
typeof s // "symbol"
注意:Symbol是原始数据类型,不能用new命令。
2.接收一个字符串作为参数用于描述Symbol
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
注意:Symbol的参数仅仅是用于描述Symbol,而不会影响它的唯一性。 简单记:Symbol的描述就像人的名字,是可以相同的,而Symbol("描述”)的返回值则是身份证.永远是唯一的。
Symbol类型转换
Symbol与其他原始数据类型的转化可以参考上图。
以上关于Symbol的内容大多参考自阮一峰大佬的ECMAScript 6 入门,大家想要深入学习可以去看一下(强烈推荐)
2.6 BigInt
定义
与Symbol一样,BigInt也是一种新的数据类型,它提供了一种方法来表示大于 2的53次方 - 1 的整数。这原本是 Javascript中可以用 Number 表示的最大数字。
BigInt
可以表示任意大的整数。
应用场景 Number只能安全的表示-9007199254740991(-(2^53-1))到9007199254740991((2^53-1))之间的数,任何超出此范围的整数值都可能失去精度。而BigInt的出现只是为了弥补这一缺陷,因为BigInt 可以表示任意大的整数。
用法
要创建BigInt,只需要在数字末尾追加n即可。
console.log( 9007199254740995n ); // → 9007199254740995n
console.log( 9007199254740995 ); // → 9007199254740996
另一种创建BigInt的方法是用BigInt()构造函数
BigInt("9007199254740995"); // → 9007199254740995n
注意:
- 1.BigInt不支持一元运算符
- 2.BigInt不能与Number进行隐式运算
- 3.不能将BigInt传递给Web api和内置的 JS 函数,这些函数需要一个 Number 类型的数字
-
Math.max(2n, 4n, 6n); // → TypeError
-
- 4.除了0n,BigInt就被视为truthy的值。
类型转换 1.BigInt转换为String
const a = 10n
console.log(String(a)) // "10"
- BigInt不能与Number发生类型转换
- 3.BigInt 转换为Boolean 除了0n,都是真值
3.那些属于引用数据类型?
3.1 Object
真正属于引用数据类型的只有Object,其他都是Object的小弟。
定义
对象是无序的数据集合,对象是键值对的数据集合。
写法
let obj = {"name": "彭一多","age":18}
let obj = new Object({"name": "彭一多","age":18})
注意:普通对象的键名是字符串,不是标识符,可以包含任意字符串。
举个栗子
let obj = {
1: 'a',
3.2: 'b',
1e2: true,
1e-2: true,
.234:true,
0xFF: true
};
变量作属性名
let p1 = "name"
let obj = {p1:"peng"}这样写,属性名为"p1"
let obj = {[p1]:"peng"}这样写,属性名为name
不加[]的属性名会自动变成字符串 加了[]则会变成变量求值 值如果不是字符串,则会自动变成字符串。
对象属性的增删改查
删除属性
delete obj.xxx或delete obj['xxx']
查看属性 查看自身所有属性名
Object.keys(obj)
查看自身所有属性名与共有属性名
console.dir(obj)
判断属性名属于自身还是共有
obj.hasOwnProperty()
查看属性值
Object.values(obj)
查看单个属性
中括号语法: obj["key"]
点语法:obj.key
注意: obj[key] !== obj['key'] // key是个变量,"key"是个常量
obj.name = obj['name']
修改属性
直接赋值
et = {"name": "frank"}
obj.name = "frank"
obj["age"] = 18
批量修改
Object.assign(obj,{age:18,gender:"man"});
第一个参数被赋值