数据类型划分 javascript
javascript中定义了6中基本数据类型(原始值类型),和一种复杂数据类型(引用类型),所谓复杂类型,其本质是由无序的名值对(key:value)组成的。 java
基本数据类型:程序员
复杂数据类型es6
原始值引用值 数组
上面提到了原始值和引用类型,可能有些人对于引用类型很熟悉,可是原始值却很陌生实际上,在ECMAScript中,变量能够存放两种类型的值,即原始值和引用值。浏览器
原始值(primitive value)数据结构
原始值是固定而简单的值,是存放在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。
引用值(reference value)函数
引用值则是比较大的对象,存放在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(pointer),指向存储对象的内存处。全部引用类型都集成自Object。
之因此说原始值是固定的,缘由是当咱们对原始值进行一些操做时结果返回的都是一个新的副本,可是对引用值操做时可能更改原值。测试
var str = 'asdfghjkl'; var obj = {name:1,age:2}; var str2 = str; var obj2 = obj; str2 = 'lkjhgfdsa'; obj2.name= 3; console.log(str,str2,obj,obj2) //asdfghjkl lkjhgfdsa {name: 3, age: 2} {name: 3, age: 2} obj == obj2 //true
经过以上代码能够明确看出字符串是按值传递的,在赋值时会新建存储空间,将str 和 str2 存放在不一样的内存空间内,对象是按引用传递的,obj = obj2时没有新建堆内存空间,而是在栈内存中存放标识符和值的引用地址,引用地址与obj的栈值相同,指向堆内存中的存储空间。spa
同时能够看到obj == obj2 返回true,这是为何?
var obj3 = {name:3,age:2} obj == obj3 //false
obj3 与 obj 的属性和属性值是同样的,可是 obj == obj3 却返回false, obj == obj2 返回true, 这说明引用类型在判断相等的时候比较的是指针,即指向对内存的地址。
提到原始值 引用值 内存地址等词,就不得不提数据的存储空间
堆栈
以前说到基本类型存储在栈内存中,复杂类型存储在堆内存中,那么什么是栈,什么是堆?
这里说的堆和栈并非一种数据结构,而是指存储空间,JVM内存划分为:寄存器,本地方法区,方法区,堆内存,栈内存,咱们说的堆栈就是这里的堆内存 和 栈内存。
栈区(stack)
由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操做方式相似于数据结构中的栈。
堆区(heap)
通常由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。
堆栈区别
1.栈内存存储的是局部变量而堆内存存储的是实体;
2.栈内存的更新速度要快于堆内存,由于局部变量的生命周期很短;
3.栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收,前提是没有任何引用。
关于堆和栈的内存空间,这里只是简单提起,强调指内存空间并不是数据结构。
不一样数据类型的存储区别
var a = undefined; var b = null; var c = 'asdfg'; var d = 123; var e = true; var f = [1,2]; var g = {name:1,age:2}; var h = g;
下图解释不一样每一种类型的存储方式
上图体现出每种数据类型在内存中的存储方式:
数据类型的判断有多种方式,下面简单介绍
typeof
typeof 用于检测数据的类型,返回值有
var u ,a = 'asdf',b = 1,c = true,d = {},e = null,f = function(){} typeof a; // string typeof b; //number typeof c; //boolean typeof u; //undefined typeof d; //object typeof e; //object typeof f; //function typeof a == 'string' //true typeof a == String //false
以上代码能够看出
instanceof
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
因为js可在多个frame之间交互,可是每一个frame有本身的全局环境,因此不一样frame和窗口之间Array是不一样的,因此没法用 a 环境下的数组去判断是不是 b 环境下的Array对象的实例
var a = 'asdffgg'; var b = 1; var c = new String('aaaa'); var arr = [1,2]; var date = new Date(); a instanceof String //false 思考:为何是false? b instanceof Number //false c instanceof Number //true 思考:a 和 c 一样是字符串结果却不同 arr instanceof Array //true arr instanceof Object //true 思考:为何 Array 和 Object都是true? date instanceof Date //true date instanceof Object //true typeof a //string 字面量的形式 返回基本类型 string typeof c //object new 一个String的实例 返回复杂类型 object
经过以上的代码段体现出如下特色和弊端:
数组便是Array的实例,又是Object的实例的缘由详解:
因为对象之间存在继承关系,因此instanceof 可以判断出 [ ].__proto__ 指向 Array.prototype,而 Array.prototype.__proto__ 又指向了Object.prototype,最终 Object.prototype.__proto__ 指向了null,标志着原型链的结束。这里关于原型链的知识点不细说
因此没法判断实例对象具体是Object的哪种类型。
constructor
constructor 属性返回对建立此对象的构造函数的引用。
当定义一个函数Fn的时候,JS引擎会为其添加一个原型prototype,并为原型添加一个constructor属性,将其指向Fn的引用
实例f的constructor是指向其构造函数Fn的,因此经过constructor咱们能够判断其构造函数是谁,从而间接的判断对象的具体类型
可是因为constructor在实现继承的时候能够被更改,实质更改是因为子类继承父类的时候可能重写了子类的原型prototype,所以使子类的prototype上的constructor发生变化,所以类型判断可能不许确
undefined 和 null没有constructor属性
toString
Object.prototype.toString 方法能够返回对象的内部属性[[Class]],格式为[object,Xxxx],其中Xxxx为具体的类型
Object.prototype.toString.call('') //"[object String]" Object.prototype.toString.call([1]) //"[object Array]" Object.prototype.toString.call(new Date) //"[object Date]"
为何不调用对象的toString方法,而是经过call调用Object.prototype.toString?
'11'.toString() //"11" [1,2].toString() //"1,2" new Date().toString() //"Fri Jun 22 2018 14:44:52 GMT+0800 (CST)"
能够看到字符串输出的是自己,数组输出的是“,”连接的数组字符串,时间类型输出的时间字符串,都不是内部属性[[Class]],缘由是实例的构造函数重写了toString方法,因此要吊用Object对象的原型伤的toString方法。
转数值类型
显示转换:Number() parseInt() parseFloat()
向Number 转换规则 ToNumber
var a = {a:1} Number(11) //11 Number('123') //123 Number(true) //1 Number(null) //0 Number(undefined) //NaN Number('') //0 Number(a) //NaN a.valueOf返回 {a:1},a.toString 返回 '[object,Object]',字符串转数值 返回NaN
parseInt parseFloat 这里不细说
隐式转换:操做符
转String类型
显示转换 toString() String()
toString:返回相应的字符串表现,
向字符串转换规则 ToString
var a = {a:1};var b = 11;var c = '11'; var e = '[1,3]';var d = true a.toString() //'[object,Object]' b.toString() //'11' c.toString() //'11' d.toString() //'true' e.toString() //'1,3'
隐式转换同+操做符数值转化
转Boolean类型
显示转换:Boolean()
向Boolean转换规则:
数字0,''空字符串,null,undefined,NaN转为false,其他转为true
隐式转换操做符 if
什么是隐式转换?
隐式转换与执行环境和操做符相关,当前操做指望某种值的时候,就会发生隐式转换,实际上面提到的具体规则点就是隐式转换的过程。
本地对象:不依赖于宿主环境的对象
Object Array Date Function RegExp String Boolean Number
单体内置对象:由ECMAScript实现提供的,不依赖于宿主环境的对象,这些对象在ECMAScript程序执行前就已经存在了
Global(全部不属于其余任何对象的属性和方法都属于Global,全局变量,方法),Math,一些数学公式和计算方法
宿主对象:由ECMAScript实现的宿主环境提供的对象,能够理解为:浏览器提供的对象。全部的BOM和DOM都是宿主对象 , Window
javascript 高级程序设计
堆和栈的概念和区别
全面解析js中的数据类型与类型转换