类型 chrome
首先明确一点,Js中的类型是针对值来讲,而不是针对变量,值就是所谓的42, 'abc', false 等能用js 操做的数据。在js 中说某某某是什么数据类型,实际上是说的这些值是什么类型。值呢?有7种数据类型: number, string, boolean, null, undefined, object, symbol. 42 就是number 类型了。怎么判断出来的,最简单的办法就是typeof 操做符了,它返回一个字符串来表示类型数组
console.log(typeof 42); // 'number'
这时,你可能想到,不对啊,之前也用typeof 操做过变量啊?也返回类型了啊。浏览器
let a = 42 console.log(typeof a); // 'number'
其实这里仍然是对值进行的类型判断,由于你不能说变量a就是number 类型,由于 js 是弱类型语言,彻底能够把从新赋值为一个变量。安全
let a = 42 console.log(typeof a); // 'number' a = 'str'; console.log(typeof a); // 'string'
这时,你就说不出变量a 是什么类型了。在js 中,若是对一个变量进行typeof 操做,必定是对当时变量所指向或所包含的值进行typeof 操做,变量没有类型,值有。函数
但使用typeof 进行类型判断的时候,它有一个bug, typeof null 返回的是'object' 而不是'null'. null 值是'null' 类型的惟一值,它居然返回了'object'. 这时,若是你就想用typeof 操做符来判断一个值是否是null, 你就要再加一个判断了。只有对象和null 执行typeof 操做时候,才返回'object', 只要找出两者的不一样就能够了,很简单,全部对象都是真值,null 是假值,!a 是true 就能够区分了。因此使用typeof 判断null的时候,以下学习
let a = null; (!a && typeof a === 'object') // true
其时 typeof 还一个小问题,就是typeof 一个函数的时候,返回的是一个'funciton', spa
let a = () => {}; console.log(typeof a); // 'function'
这可能让人产生误会,误觉得'funciton' 也是一种数据类型,其实并非,全部的函数都是对象,不过这也提供了一个判断函数的简便方法。prototype
固然,typeof 操做符还有一个好处,就是若是一个变量没有声明的话,执行typeof 操做,不会报错,而是返回undefined, 这就是提供了一个安全的操做,由于,若是你直接引用一个没有声明的变量就会报错。有时,你想判断一个变量存不存在,如要写a == undefined, 完了,报错了,引用了一个没有声明的变量a. 若是使用 typeof a == undefined, 没有问题。3d
Number类型code
Js 中,只有一种数字类型,就是Number, 实际上它是双精度的浮点型,在其它语言中称为double,也就是说Js 中没有整数类型, 所谓的整数只不过是没有小数,或小数后面全是0,如42 或42.00。 默认状况下, 数值的输出方式,都是10进制,而且会把末尾的0 去掉。
var a = 42.300; var b = 42.0; console.log(a); // '42.3' console.log(b) // 42
可是若是一个数特别大或特别小的话,它会以指数形式进行输出,在chrome 浏览器中,只要整数大于20次方,它就会转化为指向,小数的话,只要后面有7位,就会转化为指数
var a = 5000000000000000000000; var b = 0.0000005; console.log(a); // 5e+21 console.log(b) // 5e-7
使用浮点数来表示数值时,它有一个问题, 就是0.1 + 0.2 === 0.3 为false. 计算整数的时候,没有问题,计算小数就有可能出问题,那怎么办法?怎么才能让0.1 + 0.2 和0. 3 进行比较的时候,表示相等呢?一种是办法是设置一个容错的边界, 当小于这个值 的时候,就表示这两个值相等了,这个值在js 中是2的-52 次方Math.pow(2,-52),Es6 专门定义了这个常量Number.EPSILON, 只要二者进行比较小于这个数,就证实这两个值相等。
// 无限接近相等 function isCloseEnoughToEqual(n1,n2) { return Math.abs( n1 - n2 ) < Number.EPSILON; } let a = 0.1 + 0.2; let b = 0.3 console.log(isCloseEnoughToEqual(a, b)) // true
计算整数没有问题,这个整数也是有边界的, 对于double双精度浮点数,用 1 位表示符号,用 11 位表示指数,52 位表示尾数,因此浮点数表示的最大整数是2的53次方-1(Math.pow(2, 53))最小整数是-2的53次方, 即[-2^53, 2^53 - 1], 超出了这个边界,计算也是不许确
let a = 9007199254740992; // 2^53 let b = a + 1; console.log(a == b) // true
a + 1 和a 是相等的,因此出现了问题了。为些,Es6 定义了安全数值 的字面量和判断安全数值的方法 Number.MAX_SAFE_INTEGER, Number.MIN_SFTE_INTEGER
以及Number.isSafeInteger(); 固然也提供了判断整数的方法Number.isInteger();
let a = 9007199254740991; // 2^53 -1 let b = a + 1; console.log(Number.isSafeInteger(a)) // true console.log(Number.isSafeInteger(b)) // false console.log(Number.isInteger(a)) // true console.log(Number.isInteger(b)) // true
a 和 b 都是整数,但a 是安全整数,b 不是
Number 类型中的特殊值--- NaN。当咱们执行算术操做的时候,这个操做并无成功,按理说,它应该报错,可是Js 并不会,而是返回特殊的值NaN。
let a = 2 / 'foo'; console.log(a ) // NaN
咱们怎么判断值是NaN, 可能最简单的就是 它=== NaN, 可是很不幸,NaN 和它自己并不相等,NaN === NaN 返回的是false. 其次还有一个isNaN 的函数来判断NaN, 可是它也有点问题,传给isNaN的参数,首先会进行自动类型转化,看能不能转化成数字,如能就是返回true, 若是不能返回false.
let a = 2 / 'foo'; console.log(isNaN(a)) // true let b = 'foo'; console.log(isNaN(b)) // true
能够看到 b 不是NaN, 可是isNaN 仍然返回了true, 也就是说,即便isNaN() 返回了true, 咱们也不能肯定这个值是否是NaN。为了解决这个问题,ES6增长了Number.isNaN(), 若是值为NaN, 它返回ture ,不然返回false.
let a = 2 / 'foo'; console.log(Number.isNaN(a)) // true let b = 'foo'; console.log(Number.isNaN(b)) // false
Number.isNaN() 是怎么判断的呢?首先它判断这个值是否是number 类型,NaN 做为值,它实际上是number 类型
let a = 2 / 'foo'; console.log(typeof a === 'number') // true
其次才是调用isNaN 方法来判断。
Number 类型中的特殊值--- +0 和-0. Js 中的0 有两个,+0 和-0. 除了字面量的方式能够获得-0 外,使用* 或 / 操做符,也能够获得,但+ - 操做符不能。
let a = -1 * 0; let b = 0 / -1; console.log(a, b) // -0
有两个0 也没关系,可是它有几个奇怪的行为
1, +0 和 -0 使用== 或=== 比较的时候,是相等。
let a = -0; let b = 0 console.log(a === b) // true
其实它两个是不相等,因此ES6 增长了Object.is() 方法,来判断它两个并不相等。
2, -0 转化成字符串的时候,输出的结果是‘0’ ,而是不-0. JSON.stringify(-0) 也是获得'0'
let a = -0; console.log(a.toString()) // '0'
console.log(JSON.stringify(a)) // '0'
然而当一个'-0' 字符串转化数字的时候,它返回的是-0, 正常的。
+"-0"; // -0 Number( "-0" ); // -0 JSON.parse( "-0" ); // -0
null 和undefined
null 是一个关键字,不能用它做为变量名,更不能给它赋值,但undefined 不是,它能够是一个标示符,能够给它赋值,固然,这仅限在非严格模式,若是是严格模式的话,会报错。
var undefined = 2;
"use strict"; var undefined = 2; // 报错
因为undefined 能够被改写,有一个void 操做符,它后面能够是任何表达式,返回的值是undefined, 不过通常使用 void 0, 这样undefined 就不会被改写了。
console.log(void 0 === undefined) // true
对象(引用类型)
若是一个值执行typeof 操做返回 ‘object’,那么它就是引用类型,其实,还能够进行细分,它具体是对象下面的哪个类型,数组,仍是函数,使用的是Object.prototype.toString.call(值)
let a = [1,2]; let b = function(){}; let c = new Date(); console.log(Object.prototype.toString.call(a)) // '[object Array]' Array 类型 console.log(Object.prototype.toString.call(b)) // '[object Function]' Function 类型 console.log(Object.prototype.toString.call(c)) // '[object Date]' Date 类型
那对基本数据类型调用toString() 方法呢?它返回基本类型的包装类型,甚至对null, undefined 均可以调用, 返回值以下
console.log(Object.prototype.toString.call(1)) // '[object Number]' console.log(Object.prototype.toString.call('abc')) // '[object String]' console.log(Object.prototype.toString.call(false)) // '[object Boolean]' console.log(Object.prototype.toString.call(null)) // '[object Null]' console.log(Object.prototype.toString.call(undefined)) // '[object Undefined]' console.log(Object.prototype.toString.call(Symbol())) // '[object Symbol]'
数组类型
1, 删除数组元素的时候,不要用delete, 使用delete 能够把数组中的元素及元素在数组中的位置(slot)删除掉, 但不用更新数组的length 长度。
let a = [1, 2]; delete a[0]; console.log(a); console.log(a.length)
下图是chrome 浏览器的返回值。
可使用splice() 进行删除
2, 不要建立稀疏数组。当建立稀疏数组的时候,两个不相邻元素之间的slot 是不存在的,a[0] 和a[2] 之间并无slot, 尽管获取到它的值是undefined
var a = [ ]; a[0] = 1; // 没有 a[1] slot a[2] = 3; a[1]; // undefined a.length; // 3
当咱们使用构造函数建立数组时, 给它传递一个数字,它就会建立length 为参数的数组,这个数组其实也是一个稀疏数组. 好比,你传递了一个3,那么建立的数组的length 为3,咱们觉得这个数组有了3个slot, 值为undefined, 其实它没有任何的slot. 当你使用forEach 的时候,什么都没有输出
arr.forEach((item, index) => {
console.log(item);
console.log(index);
})
3, 尽管数组是对象,但千万不要做为对象进行使用,好比 a["name"] = 'Sam', 尤为是属性是数字字符串的时候,这时它会把字符串转化为数字,做为数组的元素
let a = []; a['5'] = 5; console.log(a.length) // 6
类型转化
首先要记住的是,Js中的类型转化,它获得的结果永远是基本类型,也就能够分为两种状况,基本类型和基本类型之间的转化,引用类型转化为基本类型,不可能出现基本类型转化为引用类型。类型转化出现最多就是转化成number, string, 和boolean. 这就是说,咱们在学习类型转化的时候,也要分为两种状况去学,好比转化成string, 基本类型是怎么转化string的,引用类型是怎么转化成string的。