7种数据类型
Undefined、Null、Boolean、String、Number、Symbol、Object
基本类型的变量是存放在栈区的
引用类型的值是同时保存在栈内存和堆内存中的
Undefined
通常指变量未定义。
Null
typeof null // "object"null == undefined // true
null 值表示一个空对象指针。
不同的对象在底层原理的存储是用二进制表示的,在 javaScript 中,如果二进制的前三位都为 0 的话,系统会判定为是 Object 类型。null 的存储二进制是 000 ,也是前三位,所以系统判定 null 为 Object 类型。
Boolean
Boolean(NaN); // false
String
方法:
- split:使用:
var str = "hello world";var arr = str.split('');
Number
使用 IEEE 754 格式表示整数和浮点值。
进制表示:0b—— 二进制0o—— 八进制0x或0X—— 十六进制
通常来说,有前导 0 的数值会被视为八进制,但是如果前导 0 后面有数字 8 和 9 ,则该数值被视为十进制。
如果要将 0b 和 0o 前缀的字符串数值转为十进制,要使用Number方法。Number('0b111') // 7
科学计数法
以下两种情况,JavaScript 会自动将数值转为科学计数法表示,其他情况都采用字面形式直接表示。
- 小数点前的数字多于 21 位。
- 小数点后的零多于 5 个。
正零和负零
-0 === +0 // true0 === -0 // true0 === +0 // true
几乎所有场合,正零和负零都会被当作正常的 0 。
唯一有区别的场合是,+0 或 -0 当做分母,返回的值是不相等的。
(1 / +0) === (1 / -0) // false
上面的代码之所以出现这样的结果,是因为除以正零得到 +Infinity ,除以负零得到 -Infinity ,这两者是不相等的。
浮点值
- 存储浮点值使用的内存空间是存储数值的两倍,所以 ECMAScript 总是想方设法把值转换为整数。
- 默认情况下, ECMAScript 会将小数点后至少包含 6 个零的浮点值转换为科学计数法。
- 浮点值的精确度最高可达 17 位小数,但在算术计算中远不如整数精确。例如, 0.1 + 0.2 不等于 0.3 。(之所以存在这种舍入错误,是因为使用了 IEEE 754 数值,这种错误并非 ECMAScript 所独有。其他使用相同格式的语言也有这个问题)
**NaN**
NaN是 JavaScript 的特殊值,表示“非数字”,主要出现在将字符串解析成数字出错的场合。
NaN不等于任何值,包括它本身。- 数组的
indexOf方法内部使用的是严格相等运算符,所有该方法对NaN不成立。 NaN在布尔运算时被当作false。Boolean(NaN) // false
NaN与任何数(包括它自己)的运算,得到的都是NaN。
返回 NaN 的情况:
- 零除以零;
- 无穷大除以无穷大
- 给任意负数作开方运算(
Math.pow(-1, 1/3)) - 算数运算符与不是数字或无法转换为数字的操作数一起使用时
- isNaN() 函数。接收一个参数,可以是任意数据类型,然后判断这个参数是否 “不是数值”。把一个值传给 isNaN() 后,该函数会尝试把它转换为数值。某些非数值的值可以直接转换成数值。不然转换为数值的值会导致这个函数返回 true 。
**Infinity**Infinity 表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非 0 数值除以 0 ,得到 Infinity 。
// 场景一Math.pow(2, 1024)// Infinity// 场景二0 / 0 // NaN1 / 0 // Infinity
Infinity 有正负之分,Infinity 表示正的无穷,-Infinity 表示负的无穷。Infinity 大于一切数值(除了 NaN ),-Infinity 小于一切数值(除了 NaN )。
0 * Infinity // NaN0 / Infinity // 0Infinity / 0 // InfinityInfinity + Infinity // InfinityInfinity * Infinity // InfinityInfinity / Infinity // NaNInfinity - Infinity // NaN
Infinity与null计算时,null会转成 0 ,等同于与 0 的计算。Infinity与undefined计算,返回的都是NaN- 要确定一个值是不是有限大(即介于 JavaScript 能表示的最小值和最大值之间),可以使用
isFinite()函数。
常数
- Number.EPSILON:表示1与大于1的最小浮点数之间的差,实际上是JavaScript能够表示的最小精度
- Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER:JavaScript能够准确表示的整数范围在 -2^53 到 2^53 之间(不含两个端点),超过这个范围,无法精确表示这个值。ES6 引入了
Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。由于2的53次方是一个16位的十进制数值,所以简单的法则就是,JavaScript对15位的十进制数都可以精确处理。 - Number.MIN_VALUE,最小数值,在多数浏览器中是 5e-324
- Number.MAX_VALUE,最大数值,1.7976931348623157e+308。
- Number.NEGATIVE_INFINITY 和 Number.POSITIVE_INFINITY 分别表示 -Infinity 和 Infinity 。
判断是否是数字
```javascript function isNumber(num) { return typeof num === “number” && !isNaN(num); // typeof NaN === ‘number’ }
// 或者 function isNumber(num) { return typeof num === “number” && isFinite(num); }
// 或者 function isNumber(num) { return num === !num; }
<a name="GJrQc"></a>### 取小数点后几位```javascript// 会四舍五入let num = 1.3489;num = num.toFixed(2); // 1.35
Symbol
Symbol 值通过 Symbol 函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。如果参数是一个对象,就会调用该对象的 toString 方法,将其转为字符串,然后才生成一个 Symbol 值。
注意:
Symbol函数前不能使用new命令。Symbol值作为对象属性名: 可以用方括号和Object.defineProperty,不能用点运算符。
转换规则:
Symbol值可以显式转为字符串var sym = Symbol('hello');String(sym) // 'Symbol(hello)'sym.toString() // 'Symbol(hello)'
Symbol值转布尔值Boolean(sym) // true!sym // falseif (sym) {}
-
Object
内置对象
Arguments、Array、Boolean、Date、Error、Function、Math、Number、Object、RegExp、String
Date
var myDate = new Date();myDate.getYear(); //获取当前年份(2位)myDate.getFullYear(); //获取完整的年份(4位,1970-????)myDate.getMonth(); //获取当前月份(0-11,0代表1月) // 所以获取当前月份是myDate.getMonth()+1;myDate.getDate(); //获取当前月份中的当前日(1-31)myDate.getDay(); //获取当前星期X(0-6,0代表星期天)myDate.getTime(); //获取当前时间(从1970.1.1开始的毫秒数,13位数字,精度毫秒)myDate.getHours(); //获取当前小时数(0-23)myDate.getMinutes(); //获取当前分钟数(0-59)myDate.getSeconds(); //获取当前秒数(0-59)myDate.getMilliseconds(); //获取当前毫秒数(0-999)myDate.toLocaleDateString(); //获取当前日期var mytime = myDate.toLocaleTimeString(); //获取当前时间myDate.toLocaleString(); //获取日期与时间
精度为秒(10位数字)的时间戳:
Math.round(new Date().getTime() / 1000)Math
Math.round() :四舍五入取整
- Math.ceil():向上取整
- Math.floor():向下取整
Object 的遍历
ES6 一共有 5 种方法可以遍历对象的属性:
for...in(es3就存在):遍历对象所有可继承的可枚举属性,包括原型链上的可枚举属性(不含Symbol属性)。无法保证遍历顺序,应尽量避免编写依赖对象属性顺序的代码。
注意:如果属性的 _enumerable_ 设置为 _false_ ,则无法被遍历到。如果想过滤掉原型链上的属性,可以用 hasOwnProperty 方法来进行过滤。
Object.keys(obj)(es5新增):返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含**Symbol**属性)的键名,不包含原型链上的属性。与for in + hasOwnProperty的效果一样。Object.getOwnPropertyNames(obj)(es5新增):返回一个数组,包括对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)的键名,不包含原型链上的属性。Object.getOwnPropertySymbols(obj):返回一个数组,包含对象自身的所有Symbol属性的键名。Reflect.ownKeys(obj):返回一个数组,包含对象自身的所有键名,不管键名是Symbol或字符串,也不管是否可枚举。
举个例子:
const parent = Object.create(Object.prototype, {a: {value: 1,writable: true,enumerable: true,configurable: true}})const child = Object.create(parent, {b: {value: 2,writable: true,enumerable: true,configurable: true},c: {value: 3,writable: true,enumerable: false,configurable: true}})// for infor(let i in child) {if (child.hasOwnProperty(i)) {console.log(i); // b}}// Object.keysconsole.log(Object.keys(child)) // ['b']// Object.getOwnPropertyNamesconsole.log(Object.getOwnPropertyNames(child)); // ['b', 'c']
const obj = {100: 'a', 2: 'b', 7: 'c' };Object.values(obj); // ["b", "c", "a"] 不按顺序输出
属性遍历的次序规则:
- 首先遍历所有数值键,按照数值升序排列。
- 其次遍历所有字符串,按照加入时间升序排列。
- 最后遍历所有
Symbol键,按照加入时间升序排排列。
Object的两类属性
数据属性(四个特征):
value:就是属性的值writable:决定属性能否被赋值,默认为 trueenumerable:决定for in能否枚举该属性。默认情况下,所有直接定义在对象上的属性的这个特性都是true。configurable:决定该属性能够被删除(delete)以及除 value 和 writable 特性外的其他特性是否可以被修改,默认为 truevar b = {};Object.defineProperties(b, {name: {get() {return "huangry"},configurable: false}});Object.getOwnPropertyDescriptor(b, "name"); // {set: undefined, enumerable: false, configurable: false, get: ƒ}Object.keys(b); // []b.age = 18;Object.getOwnPropertyDescriptor(b, "age"); // {value: 18, writable: true, enumerable: true, configurable: true}Object.keys(b); // ["age"]
看颜色可以知道谁是可枚举的。
```javascript
// configurable
var obj1 = {};
Object.defineProperties(obj1, {
name: {
get() {
}, configurable: false } }); Object.defineProperty(obj1, “name”, { value: “hippo” }) // TypeError Object.defineProperty(obj1, “name”, { configurable: true }) // TypeError delete obj.name; // falsereturn "huangry"
var obj2 = {name: “huangry”}; Object.defineProperties(obj2, { name: { configurable: false } }); Object.defineProperty(obj2, “name”, { value: “hippo” }) // {name: “hippo”}
访问器属性(四个特征):- `getter`:函数或 undefined ,在取属性值时被调用- `setter`:函数或 undefined ,在设置属性值时被调用- `enumerable`:决定 `for in` 能否枚举该属性- `configurable`:决定该属性能够被删除或者改变特征值可通过 `Object.getOwnPropertyDescripter` 查看属性的特征值<br />可通过 `Object.defineProperty` 来定义或改变属性的特征**对象的分类**- 宿主对象:例如 `window` 。- 内置对象- 固有对象- 原生对象- 普通对象<a name="fejet"></a># Map`Map` 是一种新的集合类型, `Map` 的大多数特性都可以通过 `Object` 类型实现,但二者之间还是存在一些细微的差异。<a name="LWXwe"></a>## 基本 API使用 `new` 关键字和 `Map` 构造函数可以创建一个空映射:```javascriptconst m = new Map()
初始化之后,可以使用 set() 方法再添加键/值对。另外,可以使用 get() 和 has() 进行查询,可以通过 size 属性获取映射中的键/值对的数量,还可以使用 delete() 和 clear()删除值。
与 Object 只能使用数值、字符串或符号作为键不同, Map 可以使用任何 JavaScript 数据类型作为键。
与 Object 类型的一个主要差异是, Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作。
选择 Object 还是 Map
- 内存占用
Object和Map的工程级实现在不同浏览器间存在明显差异,但存储单个键/值对所占用的内存数量都会随键的数量线性增加。批量添加或删除键/值对则取决于各浏览器对该类型内存分配的工程实现。不同浏览器的情况不同,但给定固定大小的内存,Map大约可以比Object多存储50%的键/值对。 - 插入性能
向Object和Map中插入新键/值对的消耗大致相当,不过插入Map在所有浏览器中一般会稍微快一点儿。对这两个类型来说,插入速度并不会随着键/值对数量而线性增加。如果代码涉及大量插入操作,那么显然Map的性能更佳。 - 查找速度
与插入不同,从大型Object和Map中查找键/值对的性能差异极小,但如果只包含少量键/值对,则Object有时候速度更快。在把Object当成数组使用的情况下(比如使用连续整数作为属性),浏览器引擎可以进行优化,在内存中使用更高效的布局。这对Map来说是不可能的。对这两个类型而言,查找速度不会随着键/值对数量增加而线性增加。如果代码涉及大量查找操作,那么某些情况下可能选择Object更好一些。 - 删除性能
使用delete删除Object属性的性能一直以来饱受诟病,目前在很多浏览器中仍然如此。为此,出现了一些伪删除对象属性的操作,包括把属性值设置为undefined或null。但很多时候,这都是一种讨厌的或不适宜的折中。而对大多数浏览器引擎来说,Map的delete()操作都比插入和查找更快。如果代码涉及大量删除操作,那么毫无疑问应该选择Map。WeakMap
ECMAScript 6新增的“弱映射”(WeakMap)是一种新的集合类型,为这门语言带来了增强的键/值对存储机制。WeakMap是Map的“兄弟”类型,其API也是Map的子集。WeakMap中的“weak”(弱),描述的是JavaScript垃圾回收程序对待“弱映射”中键的方式。
基本 API
可以使用new关键字实例化一个空的WeakMap:
const wm = new WeakMap();
初始化之后可以使用set()再添加键/值对,可以使用get()和has()查询,还可以使用delete()删除。
Set
WeakSet
类型转换
“==”
规则:
NaN不等于任何值,包括其本身- 布尔值会转成数字类型
- 数字和字符串比较,字符串会转换成数字
undefined和null除了和undefined和null相等,和其它相比都是false
ES5规范11.9.3抽象相等比较算法
- 若 Type(x) 与 Type(y) 相同,则
- 若 Type(x) 为
**Undefined**,返回true。 - 若 Type(x) 为
**Null**,返回true。 - 若 Type(x) 为
**Number**,则- 若 x 为
NaN,返回false。 - 若 y 为
NaN,返回false。 - 若 x 与 y 为相等数值,返回
true。 - 若 x 为
+0且 y 为-0,返回true。 - 若 x 为
-0且 y 为+0,返回true。 - 返回 false 。
- 若 x 为
- 若 Type(x) 为
**String**,则当 x 和 y 为完全相同的字符序列(长度相等且相同字符在相同位置)时返回true。否则,返回false。 - 若 Type(x) 为
**Boolean**,当 x 和 y 同为true或者同为false时返回true。否则,返回false。 - 当 x 和 y 为引用同一对象时返回
true。否则,返回false。
- 若 Type(x) 为
- 若 x 为
null且 y 为undefined,返回true。 - 若 x 为
undefined且 y 为null,返回true。 - 若 Type(x) 为
Number且 Type(y) 为String,返回comparison x == ToNumber(y)的结果。 - 若 Type(x) 为
String且 Type(y) 为Number,返回比较ToNumber(x) == y的结果。 - 若 Type(x) 为
Boolean,返回比较ToNumber(x) == y的结果。 - 若 Type(y) 为
Boolean,返回比较x == ToNumber(y)的结果。 - 若 Type(x) 为
String或Number,且 Type(y) 为Object,返回比较x == ToPrimitive(y)的结果。 - 若 Type(x) 为
Object且 Type(y) 为String或Number,返回比较ToPrimitive(x) == y的结果。 - 返回false。
null == undefined // truetrue == 1 //truefalse == 0 // true"123" == 123 //true"1a" == 1 //false,"1a"转成数字是NaNundefined == 0 // falseundefined == false // falsenew String("a") == "a" // truenew String("a") == new String("a") // false
X → Number
| 数据类型 | 数字类型 |
|---|---|
| 字符串 | 1) 数字转化为对应的数字 2) 其他转化为 NaN |
| 布尔类型 | 1) true 转化为 1 2) false 转化为 0 |
| null | 0 |
| undefined | NaN |
| 数组 | 1) 数组为空转化为 0; 2) 数组只有一个元素转化为对应元素; 3) 其他转化为NaN |
| 空字符串 | 0 |
Number(10); // 10Number('10'); // 10Number(null); // 0Number(''); // 0Number(true); // 1Number(false); // 0Number([]); // 0Number([1,2]); // NaNNumber('10a'); // NaNNumber(undefined); // NaN
字符串转数字
parseInt(s); // 解析时会跳过任意数量的前导空格,尽可能解析更多数值字符parseFloat(s);Number(s); // 字符中不能出现非数字的字符,否则将返回 NaN
parseInt && parseFloat
paeseInt 方法用于将字符串转为整数。如果字符串头部有空格,空格会被自动去除。如果 parseInt 的参数不是字符串,则会先转为字符串再转换。字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。
如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回 NaN 。
所以, parseInt 的返回值只有两种可能,要么是一个十进制整数,要么是 NaN 。
如果字符串以 0x 或 0X 开头, parseInt 会将其按照十六进制数解析。
对于那些会自动转为科学计数法的数字, parseInt 会将科学计数法的表示方法视为字符串,因此导致一些奇怪的结果。
parseInt('1e+21') // 1
parseInt 方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数。默认情况下, parseInt 的第二个参数为 10 ,即默认是十进制转十进制。
parseInt('1000', 2) // 8parseInt('1000', 6) // 216
如果第二个参数不是数值,会被自动转为一个整数。这个整数只有在 2 到 36 之间,才能得到有意义的结果,超出这个范围,则返回 NaN 。如果第二个参数是 0 、 undefined 和 null ,则直接被忽略。
如果字符串包含对于指定进制无意义的字符,则从最高位开始,只返回可以转换的数值。如果最高位无法转换,则直接返回 NaN 。
X → String
对于原始类型来说,转字符串类型会默认调用 toString() 方法。
| 数据类型 | String类型 |
|---|---|
| 数字 | 转化为数字对应的字符串 |
| true | 转化为字符串 “true” |
| null | 转化为字符串 “null” |
| undefined | 转化为字符串 “undefined” |
| Object | 转化为 “[object Object]” |
x → Boolean
| 数据类型 | 转化为 true 的值 | 转换为 false 的值 |
|---|---|---|
| Boolean | true | false |
| String | 非空字符串 | 空字符串 |
| Number | 非零数值(包括无穷值) | 0 、 NaN |
| Object | 任意对象 | null |
| Undefined | N/A(不存在) | undefined |
Boolean("") //falseBoolean(undefined) // falseBoolean(null) // falseBoolean(NaN) // falseBoolean(false) // falseBoolean(0) // falseBoolean({}) // trueBoolean([]) // true
判断数据类型
typeof
返回的值有:
"undefined""boolean""string""number""object" 表示值为对象(而不是函数)或 null"function""symbol"
除了 null 类型以及 Object 类型不能准确判断外,其他数据类型都可能返回正确的类型。
既然 typeof 对对象类型都返回 Object 类型情况的局限性,我们可以使用 instanceof 来进行判断某个对象是不是另一个对象的实例。返回值的是一个布尔类型。
typeof undefined // 'undefined'typeof null // 'object'typeof Symbol() // 'symbol'typeof Function // 'function'typeof [] // 'object'typeof {} // 'object'
instanceof
Object.prototype.toString.call()
最好的
Object.prototype.toString.call(1) // "[object Number]"Object.prototype.toString.call('hi') // "[object String]"Object.prototype.toString.call({a:'hi'}) // "[object Object]"Object.prototype.toString.call([1,'a']) // "[object Array]"Object.prototype.toString.call(true) // "[object Boolean]"Object.prototype.toString.call(() => {}) // "[object Function]"Object.prototype.toString.call(null) // "[object Null]"Object.prototype.toString.call(undefined) // "[object Undefined]"Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"
参考链接:
