1、JavaScript中的数据类型
? JavaScript中的数据一共有八种:Number 、String 、Boolean 、Undefined 、Null 、Object 、Symobl 、BigInt ;
? 主要分为两种,分别是: 原始数据类型 、引用数据类型 ;
1.1 原始数据类型
? 原始数据类型有: Number 、String 、Boolean 、Undefined 、Null 、Symobl 、BigInt ;
其中 Symobl、BigInt是ES6新增的数据类型; ? Symobl :通过Symobl创建的数据类型是独一无二的并不可被改变,可以用于解决可能出现的全局变量冲突以及对象属性不唯一的问题; ? BigInt :表示一种数字类型的数据,可以表示任意精度格式的整数,可以安全的存储与操作即使超出了Number所能表示的范围的大整数;
1.2 引用数据类型
? 引用数据类型只有Object ;
Object类型是一个大类,Array 、Function 、Date 等内置对象都是Object类型的子类;
1.3 原始数据类型与引用数据类型的区别
其主要区别在于他们的存储位置的不同: 引用数据类型 :数据存储在堆 内存中,指向数据的指针,存放在栈内存中,当访问引用数据的时候,先是在栈内存中检索指针,然后通过指针找到数据; 原始数据类型 :数据直接存储在栈 内存中; ? 堆内存与栈内存的区别
? 堆与栈的概念存在于操作系统内存与数据结构中;
数据结构中的堆与栈 :在数据结构中,栈中的数据存取方式是先进后出,而堆是一个优先队列,按照优先级来进行排序的,优先级可以按照大小来规定; ? 操作系统内存中的堆与栈 :在操作系统中,内存被分为堆区与栈区。 ? 栈区内存由编译器自动分配与释放,用于存放函数的参数值,局部变量的值等,其操作方式类似于数据结构中的栈。 ?堆区内存一般由开发者分配与释放,若开发者不对堆区内存进行释放,那么程序结束时,可能会由垃圾回收机制进行回收。
2、检测数据类型的方法
2.1 typeof
在JavaScript中,typeof是一个运算符,通过该方法可以检测出数据的类型。
console.log(typeof 1)
console.log(typeof '1')
console.log(typeof true)
console.log(typeof undefined)
console.log(typeof null)
console.log(typeof function(){})
console.log(typeof {})
console.log(typeof [])
由上方可以看出,通过typeof检测引用数据类型的时候,除Function外,检测出的类型都是Object类型,甚至连null检测出来的都是Object类型; ? 原因是因为,typeof 操作符是按照数据在计算机底层存储的二进制结果进行检测的。而null的二进制为:000000,所有的Object类型的数据在计算机底层存储的二进制都是000开头的,所以typeof无法很好的识别出Object类型与null数据类型;
2.2 instanceof
运行原理 :检测实例对象是否是该构造函数的实例对象,主要通过查询被检测对象的原型链上,能否找到与目标对象相同的原型;
console.log(1 instanceof Number)
console.log('1' instanceof String)
console.log(true instanceof Boolean)
console.log(function(){} instanceof Function)
console.log({} instanceof Object)
console.log([] instanceof Array)
通过上方可以看出,instanceof只能判断引用类型,不能判断基本数据类型,但是我们通过构造函数的方式去创建一个Number类型的值,就可以通过instanceof进行检测。
const a = new Number(1)
const b = Number(2)
const c = 3
console.log(a, a instanceof Number)
console.log(b, b instanceof Number)
console.log(c, c instanceof Number)
手写 instanceof 方法
function myInstanceof(instance, type) {
let proto = Object.getPrototypeOf(instance)
let prototype = type.prototype
while (true) {
if (!proto) return false;
if (proto === prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
console.log(myInstanceof(1, Number))
console.log(myInstanceof('1', String))
console.log(myInstanceof(true, Boolean))
console.log(myInstanceof({}, Object))
console.log(myInstanceof([], Array))
console.log(myInstanceof(function () {}, Function))
2.3 constructor
constructor 属性,不仅可以让实例对象访问其构造函数,还可以做数据类型的判断;
console.log((1).constructor === Number);
console.log(('1').constructor === String);
console.log((true).constructor === Boolean);
console.log(({}).constructor === Object);
console.log((function () {}).constructor === Function);
console.log(([]).constructor === Array);
2.4 Object.prototype.toString.call()
toString是Object原型上的方法,Array、function等类型作为Object 的实例,都重写了toString方法。不同的对象类型调用toString方法时,调用的都是重写后的方法(function类型返回内容为函数体的字符串,Array类型返回内容为元素组成的字符串等),而不会去调用Object上原型toString方法(返回对象的具体数据类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,想要得到对象的具体类型,应该调用原型上的toString方法。
let obj = {
name:'link',
age:18
}
function fun() {
return 1
}
let arr = [1, 2, 3]
console.log(obj.toString())
console.log(arr.toString())
console.log(fun.toString())
let obj = {
name: 'link',
age: 18
}
function fun() {
return 1
}
let arr = [1, 2, 3]
console.log(Object.prototype.toString.call(1))
console.log(Object.prototype.toString.call('1'))
console.log(Object.prototype.toString.call(true))
console.log(Object.prototype.toString.call(undefined))
console.log(Object.prototype.toString.call(null))
console.log(Object.prototype.toString.call(obj))
console.log(Object.prototype.toString.call(fun))
console.log(Object.prototype.toString.call(arr))
3、类型转换
在JavaScript中数据类型转换分为两种,分别是显示类型转换、隐式类型转换; ? 显示类型转换 :强制类型转换,由开发人者通过内置方法转换数据类型,如:Number(‘123’); ? 隐式类型装换 :当对不同类型的值使用运算符的时候,值会在类型之间自动的切换;
3.1 == 操作符号的类型转换规则
对于 == 操作符来说,如果对比的双方的类型不同,就会进行类型的转换,其判断流程如下:
- 首先会判断两者类型是否相同;
- 类型不同就进行转换;
- 判断是否在对比
null 和 undefined ,如果是的话,就返回true - 判断两者类型是否为
String 和 Number ,是的话,会将String 类型转换为Number 类型 - 判断其中一方是否为
Boolean 类型,如果是就会把Boolean 转换为number 类型进行比较 - 判断其中一方是否为
Object 且另一方为String 、Number 或者 Symobl ,是的话,就会把Object 转为原始类型进行判断。 流程图如下
3 == true
'0' == false
'0' == 0
3.2 其他类型转String 的规则
Null 和 Undefined 类型 ,null 转换为 "null" ,undefined 转换为 "undefined" ;Boolean 类型,true 转换为 "true" ,false 转换为 "false" 。Number 类型的值直接转换,不过那些极小和极大的数字会使用指数形式。Symbol 类型的值直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误。- 对普通对象来说,除非自行定义
toString() 方法,否则会调用 toString() (Object.prototype.toString())来返回内部属性 [[Class]] 的值,如"[object Object]" 。如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。
3.3 其他类型转Number 的规则
Undefined 类型的值转换为 NaN 。Null 类型的值转换为 0 。Boolean 类型的值,true 转换为 1 ,false 转换为 0 。String 类型的值转换如同使用 Number() 函数进行转换,如果包含非数字值则转换为 NaN ,空字符串为 0 。Symbol 类型的值不能转换为数字,会报错。- 对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。
为了将值转换为相应的基本类型值,抽象操作 ToPrimitive 会首先(通过内部操作 DefaultValue )检查该值是否有valueOf() 方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString() 的返回值(如果存在)来进行强制类型转换。
【注意】如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。
3.4 其他类型转Boolean 的规则
以下这些是假值:
undefined null false +0 、-0 和 NaN ""
假值的布尔强制类型转换结果为 false 。从逻辑上说,假值列表以外的都应该是真值。
3.5 补充
首先要介绍ToPrimitive 方法,这是 JavaScript 中每个值隐含的自带的方法,用来将值 (无论是基本类型值还是对象)转换为基本类型值。如果值为基本类型,则直接返回值本身;如果值为对象,其看起来大概是这样:
ToPrimitive(obj,type)
type 的值为number 或者string 。
(1)当type为number时规则如下:
- 调用
obj 的valueOf 方法,如果为原始值,则返回,否则下一步; - 调用
obj 的toString 方法,后续同上; - 抛出
TypeError 异常。
(2)当type为string时规则如下:
- 调用
obj 的toString 方法,如果为原始值,则返回,否则下一步; - 调用
obj 的valueOf 方法,后续同上; - 抛出
TypeError 异常。
可以看出两者的主要区别在于调用toString 和valueOf 的先后顺序。默认情况下:
- 如果对象为
Date 对象,则 type 默认为 string ; - 其他情况下,
type 默认为 number 。
总结上面的规则,对于 Date 以外的对象,转换为基本类型的大概规则可以概括为一个函数:
var objToNumber = value => Number(value.valueOf().toString())
objToNumber([]) === 0
objToNumber({}) === NaN
而 JavaScript 中的隐式类型转换主要发生在+、-、*、/ 以及==、>、< 这些运算符之间。而这些运算符只能操作基本类型值,所以在进行这些运算前的第一步就是将两边的值用ToPrimitive 转换成基本类型,再进行操作。
3.5.1 + - * / 操作符
+ 操作符的两边有至少一个 string 类型变量时,两边的变量都会被隐式转换为字符串;其他情况下两边的变量都会被转换为数字。
1 + '23'
1 + false
1 + Symbol()
'1' + false
false + true
- 、* 、 / 操作符转换出来的也是数字
1 * '23'
1 * false
4 / 2
'2' - 1
3.5.2 < > 比较符
如果两边都是字符串,则比较字母表顺序:
'ca' < 'bd'
'a' < 'b'
其他情况下,转换为数字在进行比较:
'12' < 13
false > -1
以上说的是基本类型的隐式转换,而对象会被ToPrimitive 转换为基本类型再进行转换:
var a = {}
a > 2
a.valueOf()
a.toString()
Number(a.toString())
NaN > 2
再举一个小栗子:
var a = {name:'Jack'}
var b = {age: 18}
a + b
a.valueOf()
a.toString()
b.toString()
a + b
相关文章
……
|