js数据类型是js里面的基础,不过,也很容易出错,熟能生巧,所以得经常复习
最新的 ECMAScript 标准定义了哪 8 种数据类型
7 种基础类型:
- Boolean、Number、String
- Null、Undefined
- BigInt、Symbol(ES6)
1 种引用类型 :Object
null和undefined的区别
null表示”没有对象”,即该处不应该有值
undefined表示”缺少值”,就是此处应该有一个值,但是还没有定义
1 2 3 4 5
| Number(null)
Number(undefined)
|
检查数据类型的方法
- typeof是检测一个变量是不是基本数据类型的最佳工具
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| console.log(typeof ""); console.log(typeof 1); console.log(typeof true); console.log(typeof undefined); console.log(typeof null); console.log(typeof {}); console.log(typeof []); console.log(typeof function(){});
console.log(typeof Symbol("foo"))
|
使用 typeof 可以准确判断出除 null 以外的基本类型,以及 function 类型、null 会被 typeof 判断为 object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| typeof Function; typeof new Function(); typeof function() {};
typeof Array; typeof Array(); typeof new Array(); typeof [];
typeof Boolean; typeof Boolean(); typeof new Boolean();
typeof Math; typeof Math(); typeof new Math();
|
构造函数 Array(..) 不要求必须带 new 关键字。不带时,它会被自动补上。 因此 Array(1,2,3) 和 new Array(1,2,3) 的效果是一样的
不推荐使用这种引用类型的基本包装对象
1 2 3 4
| var a = new Boolean(false); if (!a) { console.log('Oops'); }
|
- instanceof 检测当前实例是否隶属于某各类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| console.log("1" instanceof String);
new Number(5) instanceof Number console.log(1 instanceof Number); console.log(true instanceof Boolean); console.log({} instanceof Object); console.log([] instanceof Array); console.log(function(){} instanceof Function)
console.log(null instanceof Null); console.log(undefined instanceof Undefined);
|
1 2 3 4 5 6 7 8 9
| let num = 1 num.__proto__ === Number.prototype num instanceof Number
num = new Number(1) num.__proto__ === Number.prototype num instanceof Number
num.__proto__ === (new Number(1)).__proto__
|
- constructor 可以查看目标的构造函数
1 2 3 4 5 6 7 8 9 10 11
| console.log(("1").constructor === String); console.log((1).constructor === Number); console.log((true).constructor === Boolean); console.log(({}).constructor === Object); console.log(([]).constructor === Array); console.log((function() {}).constructor === Function);
|
对于 undefined 和 null,如果尝试读取其 constructor 属性,将会进行报错。
并且 constructor 返回的是构造函数本身,一般使用它来判断类型的情况并不多见
- Object.prototype.toString.call()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| console.log(Object.prototype.toString.call("1")); console.log(Object.prototype.toString.call(1)); console.log(Object.prototype.toString.call(null)); console.log(Object.prototype.toString.call(undefined)); console.log(Object.prototype.toString.call(true)); console.log(Object.prototype.toString.call({})); console.log(Object.prototype.toString.call([])); console.log(Object.prototype.toString.call(function () {});
Object.prototype.toString.call(Symbol(1))
|
数据类型转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| 强制转换 Number() 原始类型:有不能转为数字的,就是NaN Number(false) => 0 Number(true) => 1 Number(undefined) => NaN Number(null) => 0 Number("1.2") => 1.2 Number("12") => 12 Number("1.2.3") => NaN Number(new object()) => NaN Number(50) => 50 Number({}) => NaN String() 原始类型值的转换规则 数值:转为相应的字符串。 字符串:转换后还是原来的值。 布尔值:true转为"true",false转为"false"。 undefined:转为"undefined"。 null:转为"null"。 String({a: 1}) => "[object Object]" String([1, 2, 3]) => "1,2,3" Boolean() false undefined null -0 0或+0 NaN false '' true 所有对象,包括{}、布尔对象new Boolean(false) 自动转换 场景: 不同类型的数据互相运算 123 + 'abc' => "123abc" 对非布尔值类型的数据求布尔值 if ('abc') 对非数值类型的数据使用一元运算符(即“+”和“-”) + {foo: 'bar'} => NaN 本质: 以强制类型为基础,转为需要的number、string、boolean
|
+ 运算符
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| console.log(1 + '1')
console.log(1 + true)
console.log(1 + false)
console.log(1 + undefined)
console.log('lucas' + true)
|
当使用 + 运算符计算 string 和其他类型相加时,都会转换为 string 类型;其他情况,都会转换为 number 类型,但是 undefined 会转换为 NaN,相加结果也是 NaN
当使用 + 运算符计算时,如果存在复杂类型,那么复杂类型将会转换为基本类型,再进行运算
“对象类型转基本类型”,具体过程:
对象在转换基本类型时,会调用该对象上 valueOf 或 toString 这两个方法,该方法的返回值是转换为基本类型的结果
具体是调用valueOf 还是toString, 这是ES规范所决定的,实际上这取决于内置的toPrimitive调用结果。主观上说,就是这个对象倾向于转换成什么,就会优先调用哪个方法,如果倾向于Number类型,则会优先调用valueOf,如果倾向于转换String类型,就只调用toString
《JavaScript 高级程序设计》以及《你不知道的 JavaScript》介绍对象转换成基本类型,会先调用valueOf,再调用toString
valueOf 以及toString是可以被开发者重写的。比如:
1 2 3 4 5 6 7 8
| const foo () { valueOf () { return 27 } toString() { return 'cm' } }
|
这时候再调用
这里“隐式转换“,使用toString方法将foo对象转换成基本数据类型
这时候的隐式转换倾向于使用valueOf方法,将其转换成基本数据类型,然后进行相加
总结:
对于 + 规则,如果两边都是Number,其规则是:
- 如果 + 两边存在 NaN, 则结果为 NaN (typeOf NaN 是 ‘number’)
- 如果是 Infinity + Infinity , 结果是 Infinity
- 如果是 -Infinity + (-Infinity) , 结果是 -Infinity
- 如果是 Infinity + (-Infinity) , 结果是 NaN
如果 + 两边,至少有一个是字符串:
- 如果都是字符串,则进行字符串拼接
- 如果两边只有一个值是字符串,则将另外的值转为字符串,再进行拼接
- 如果两边有一个对象,则调用valueOf()或者 toString()方法取得值,转为基本类型再进行拼接
什么情况下会发生布尔值的隐式强制类型转换
(1) if (..) 语句中的条件判断表达式。
(2) for ( .. ; .. ; .. ) 语句中的条件判断表达式(第二个)。
(3) while (..) 和 do..while(..) 循环中的条件判断表达式。
(4) ? : 中的条件判断表达式。
(5) 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。
|| 与 &&
== 与 ===
常见的误区是“== 检查值是否相等,=== 检查值和类型是否相等”
正确的解释是:“== 允许在相等比较中进行强制类型转换,而 === 不允许。”
显示转换
我们也可以进行显示转换,往往使用Number, Boolean, String, parseInt 等方法进行转换
经典题目
a == 1 && a == 2 && a == 3 可能为 true 吗?
直观分析,a不可能是基本 Number 类型, 这是不可能为true, 因此我们应该考虑a是一个对象,转换成基本类型,再进行运算
方案一: 改写valueOf, toString方法
1 2 3 4 5 6 7
| const a = { value: 1, toString () { return a.value++; } } a == 1 && a == 2 && a == 3
|
重写valueOf方法同样也能做到
方案二: Object.defineProperty()将a定义为一个全局对象window的属性
1 2 3 4 5 6 7
| let value = 0 Object.defineProperty(window, 'a', { get: function () { return ++value } }) a == 1 && a == 2 && a == 3
|
封装一个 javascript 的类型判断函数?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function getType(value) { if (value === null) { return value + ""; } if (typeof value === "object") { let valueClass = Object.prototype.toString.call(value), type = valueClass.split(" ")[1].split(""); type.pop(); return type.join("").toLowerCase(); } else { return typeof value } }
|