JS数据类型了解多少
数据的运用多依赖于变量。变量:是用于存放数据的容器。其本质是程序在内存中申请的一块用来存放数据的空间。JS中,所有的变量都是保存在栈内存中的。
为什么需要数据类型?
在计算机中,不同的数据所需占用的存储空间不同,为了充分利用存储空间,于是定义了不同的数据类型。而且,不同的数据类型,寓意也不同。
JavaScript 是一种「弱类型语言」,JS 的变量数据类型,是在程序运行的过程中,根据等号右边的值来确定的。
声明与定义
var x;//声明
var y=1;//定义
声明是起了变量名,给变量赋值则为定义,声明未赋值,默认补值undefined。
JS目前有七种通用的数据类型
- 基本数据类型(值类型):String 字符串、Number 数值、Boolean 布尔值、Null 空值、Undefined 未定义。
- 引用数据类型(引用类型):Object 对象。
- ES6新增数据类型:Symbol 定义对象的唯一属性名(对这个属性暂时没太深入理解)
注意:内置对象 Function、Array、Date、RegExp、Error等都是属于 Object 类型。也就是说,除了那五种基本数据类型之外,其他的,都称之为 Object类型。
使用typeof(xx)检测xx的数据类型
数据类型之间最大的区别:
- 基本数据类型:参数赋值的时候,传数值(参数指向独立内存空间)。
基本数据类型的值,直接保存在栈内存中。值与值之间是独立存在,修改一个变量不会影响其他的变量。
var a = 23;
var b = a;
a++;
console.log(a); // 打印结果:24
console.log(b); // 打印结果:23
- 引用数据类型:参数赋值的时候,传地址(参数指向同一片内存空间)。
对象是保存到堆内存中的。每创建一个新的对象,就会在堆内存中开辟出一个新的空间;而变量保存了对象的内存地址(对象的引用),保存在栈内存当中。如果两个变量保存了同一个对象的引用,当一个通过一个变量修改属性时,另一个也会受到影响。
var obj1 = new Object();
obj1.name = 'smyh';
// 让 obj2 等于 obj1
var obj2 = obj1;
// 修改 obj1 的 name 属性
obj1.name = 'vae';
console.log(obj1.name); // 打印结果:vae
console.log(obj2.name); // 打印结果:vae
数据类型内存模型图
注:变量名是有专门的表来维护的–变量表,此处说的是数据值保存的位置
原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
延伸——垃圾回收站
它是专门释放对象内存的一个程序。
(1)在底层,后台伴随当前程序同时运行;引擎会定时自动调用垃圾回收期;
(2)总有一个对象不再被任何变量引用时,才释放。let obj=[]; obj=null;//释放一个引用
String
字符串里面的值不可被改变。虽然可以通过拼接等等实现貌似值的改变,但其实是指向的地址变了,内存中新开辟了一个内存空间。
新: ES6 模板字符串 反引号 `` ${}类似一个函数体,可以执行函数,获取数值,遍历等等
var name = 'xx';
var age = '26';
console.log('我是' + name + ',age:' + age); //传统写法
console.log(`我是${name},age:${age}`); //ES6 写法。注意语法格式
Number
在 JS 中,只要是数,就是 Number 数值型的。无论整浮、浮点数(即小数)、无论大小、无论正负,都是 Number 类型的。
数值范围
由于内存的限制,ECMAScript 并不能保存世界上所有的数值。
- 最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
- 最小值:Number.MIN_VALUE,这个值为: 5e-324
如果使用 Number 表示的变量超过了最大值,则会返回Infinity。
- 无穷大(正无穷):Infinity
- 无穷小(负无穷):-Infinity
注意:typeof Infinity的返回结果是number。
NaN
NaN:是一个特殊的数字,表示Not a Number,非数值。
出现条件:无法转化为数字的数据使用了非+运算符号进行“运算“
检测方法:isNaN() console.log(isNaN('a')) //true
- NaN 与任何值都不相等,包括 NaN 本身。
- typeof NaN的返回结果是 number。
- undefined做任何数值运算都是NaN
- null做数值运算被视为0
console.log('a'-2) //NaN
console.log(typeof(NaN)) //number
console.log(isNaN('a')) //true
console.log(NaN==NaN)//false
连字符和加号的区别
如果加号两边都是 Number 类型,此时是数字相加。否则,就是连字符(用来连接字符串)。
console.log('2'+2-6) //16 ‘2’+2=‘22’ ‘22’-6->22-6=16(隐式转换)
浮点数的运算
运算精度问题
在JS中,整数的运算基本可以保证精确;但是小数的运算,可能会得到一个不精确的结果。所以,千万不要使用JS进行对精确度要求比较高的运算。
var a = 0.1 + 0.2;
console.log(a); //打印结果:0.30000000000000004
这是因为,计算机在做运算时,所有的运算都要转换成二进制去计算。然而,有些数字转换成二进制之后,无法精确表示。比如说,0.1和0.2转换成二进制之后,是无穷的,因此存在浮点数的计算不精确的问题。
如果只是一些简单的精度问题,可以使用 toFix() 方法进行小数的截取。
市面上有很多针对数学运算的开源库,比如decimal.js、 Math.js。
Math.js:属于很全面的运算库,文件很大,压缩后的文件就有500kb。如果你的项目涉及到大型的复杂运算,可以使用 Math.js。
decimal.js:属于轻量的运算库,压缩后的文件只有32kb。大多数项目的数学运算,使用 decimal.js 足够了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/decimal.js/10.2.0/decimal.min.js"></script>
<script>
console.log('加法:');
var a = 0.1;
var b = 0.2;
console.log(a + b);
console.log(new Decimal(a).add(new Decimal(b)).toNumber());
console.log('减法:');
var a = 1.0;
var b = 0.7;
console.log(a - b);
console.log(new Decimal(a).sub(new Decimal(b)).toNumber());
console.log('乘法:');
var a = 1.01;
var b = 1.003;
console.log(a * b);
console.log(new Decimal(a).mul(new Decimal(b)).toNumber());
console.log('除法:');
var a = 0.029;
var b = 10;
console.log(a / b);
console.log(new Decimal(a).div(new Decimal(b)).toNumber());
</script>
</body>
</html>
Boolean
布尔型有两个值:true 和 false。布尔型和数字型相加时, true 按 1 来算 ,false 按 0 来算。
Null
- Null 类型的值只有一个,就是 null。比如 let a = null。
- 使用 typeof 检查一个 null 值时,会返回 object。
var myObj = null;
cosole.log(typeof myObj); // 打印结果:object
Undefined
- Undefined 类型的值只有一个,就是 undefind。比如 let a = undefined。
- 使用 typeof 检查一个 undefined 值时,会返回 undefined。
变量已声明,未赋值时 let x; console.log(x);
打印无返回值的函数function foo(){};console.log(foo())
typeof未声明的变量
console.log(typeof a)
not defined
未声明就调用了。
console.log( a+1)
null & undefined
undefined:定义未赋值 null:定义赋值空
空也相当于没有值,故 == true 但它们类型是不一样的 故=== false
console.log( null==undefined) //true
console.log( null===undefined) //false
有区别也有相似性
其中一个区别是,和数字运算时: undefined做任何数值运算都是NaN, null做数值运算被视为0
- 10 + null 结果为 10。
- 10 + undefined 结果为 NaN。
Object
ECMAScript中的对象其实就是一组数据和功能的集合。通过new操作符后跟要创建的对象类型的名称来创建。
var obj = new Object();
内置对象 Function、Array、Date、RegExp、Error等都是属于 Object 类型。也就是说,除了那五种基本数据类型之外,其他的,都称之为 Object类型。
JS中的类继承模式类似java中的基类和派生类的关系。派生类对象存储了基类的数据成员。
派生类的实例对象可以 访问基类的属性,方法。
JS中的内置对象Date、RegExp、Number、Function… 可以看做派生类、Object可以被看做 基类。
而特殊的是,javascript中Object这个基类,同时又是 Function这个派生类的 实例对象。
每个Object类型的实例共有的属性和方法:
- constructor: 保存着用于创建当前对象的函数。
- hasOwnProperty:用于检测给定的属性在当前对象的实例中是否存在。
- isPrototypeOf : 用于检查传入的对象是否是当前对象的原型
- propertyIsEnumerble : 用于检查给定属性能否使用for-in来枚举
- toLocaleString() : 返回对象的字符串表示。
- toString() : 返回对象的字符串表示。
- valueOf() : 返回对象的字符串,数值,或布尔表示。通常和toString() 返回的值相同。
Symbol
Symbol 类型的对象永远不相等,即便创建的时候传入相同的值。因此,可以用解决属性名冲突的问题(适用于多少编码),做为标记。
暂时了解不多:ES6学习☞Symbol
typeof & constructor
typeof
typeof 操作符来查看 JavaScript 变量的数据类型
typeof "John" // 返回 string
typeof 3.14 // 返回 number
typeof NaN // 返回 number
typeof false // 返回 boolean
typeof [1,2,3,4] // 返回 object
typeof {name:'John', age:34} // 返回 object
typeof new Date() // 返回 object
typeof function () {} // 返回 function
typeof myCar // 返回 undefined (如果 myCar 没有声明)
typeof null // 返回 object
如果对象是 JavaScript Array 或 JavaScript Date ,我们就无法通过 typeof 来判断他们的类型,因为都是 返回 object。
constructor
constructor 属性返回所有 JavaScript 变量的构造函数。
console.log('free'.constructor)//[Function: String]
console.log((3.14).constructor)//[Function: Number]
console.log(false.constructor)//[Function: Boolean]
console.log([1,2].constructor)//[Function: Array]
console.log({name:'free',age:'24'}.constructor)//[Function: Object]
console.log(new Date().constructor)//[Function: Date]
console.log(function (){}.constructor)//[Function: Function]
巧妙利用toString(),检测对象的实际类型。
function isArray(myArray){ //巧妙检测数据类型
return myArray.constructor.toString().indexOf('Array')>-1
}
console.log(isArray([1,2,3]))//true
类型转换
隐式转换和显示转换
通过 JavaScript 自身自动转换,通过使用 JavaScript 函数。
隐式类型: 部分算术运算符
显示转换:Number(),Boolean(),String(),parseInt()等