前两天看到kraaas
大神的关于基本数据类型和引用类型的区别的文章以为写得很是不错,就想着在其基础上加上本身平时看到的一些知识点和理解,因此就有了如下的文章segmentfault
js基本数据类型包括:undefined,null,number,boolean,string.基本数据类型是按值访问的,就是说咱们能够操做保存在变量中的实际的值数组
任何方法都没法改变一个基本类型的值,好比一个字符串:spa
var name = "change"; name.substr();//hang console.log(name);//change var s = "hello"; s.toUpperCase()//HELLO; console.log(s)//hello
经过这两个例子,咱们会发现原先定义的变量name的值始终没有发生改变,而调用substr()和toUpperCase()方法后返回的是一个新的字符串,跟原先定义的变量name并无关系设计
或许有人会有如下的疑问,看代码:指针
var name = "change"; name = "change1"; console.log(name)//change1
这样看起来name的值“改变了”
其实,var name = "change",这里的基础类型是string,也就是"change",这里的"change"是不能够改变的,name只是指向"change"的一个指针,指针的指向能够改变,因此你能够name = "change1".此时name指向了"change1",同理,这里的"change1"一样不能够改变code
也就是说这里你认为的改变只是“指针的指向改变”对象
这里的基础类型指的是"change",而不是name,要区分清楚blog
var p = "change"; p.age = 29; p.method = function(){console.log(name)}; console.log(p.age)//undefined console.log(p.method)//undefined
经过上面的代码,咱们知道不能给基本类型添加属性和方法,也再次说明基本类型是不可变的图片
若是从一个变量向另外一个变量赋值基本类型的值,会在变量对象上建立一个新值,而后把该值复制到为新变量分配的位置上ip
var a = 10; var b = a; a++; console.log(a)//11 console.log(b)//10
上面的代码中,a中保存的值是10.当使用a的值来初始化b时,b中也保存了值10.但b中的10和a中的10是彻底独立的.b中的值知识a中值的一个副本.因此这两个变量能够参与任何操做而不会相互影响.以下图:
var person1 = '{}'; var person2 = '{}'; console.log(person1 == person2); // true
假若有如下几个基本类型的变量:
var name = "jozo"; var city = "guangzhou"; var age = 22;
那么它的存储结构以下图:
栈区包括了变量的标识符和变量的值
js中除了上面的基本类型以外就是引用类型了,也能够说就是对象了,好比:Object,Array,Function,Data等
var o = {x:1}; o.x = 2;//经过修改对象属性值更改对象 o.y = 3;再次更改对象,给它增长一个属性 var a = [1,2,3]; a[0] = 0;//更改数组的一个元素 a[3] = 4;//给数组增长一个元素
var person = {}; person.name = "change"; person.say = function(){alert("hello");} console.log(person.name)//change console.log(person.say)//function(){alert("hello");}
先看如下代码:
var a = {}; var b= a; a.name = "change"; console.log(a.name)//change; console.log(b.name)//change b.age = 29; console.log(a.age)//29 console.log(b.age)//29
当从一个变量向另外一个变量赋值引用类型的值时,一样也会将储存在变量中的对象的值复制一份放到为新变量分配的空间中.引用类型保存在变量中的是对象在堆内存中的地址,因此,与基本数据类型的简单赋值不一样,这个值的副本其实是一个指针,而这个指针指向存储在堆内存的一个对象.那么赋值操做后,两个变量都保存了同一个对象地址,而这两个地址指向了同一个对象.所以,改变其中任何一个变量,都会互相影响
他们的关系以下图:
所以,引用类型的赋值实际上是对象保存在栈区地址指针的赋值,因此两个变量指向同一个对象,任何的操做都会互相影响.
var person1 = {}; var person2 = {}; console.log(person1 == person2)//false
为何两个对象看起来一摸同样,可是却不相等呢?
由于引用类型的比较是引用的比较,换句话说,就是比较两个对象保存在栈区的指向堆内存的地址是否相同,此时,虽然p1和p2看起来都是一个"{}",可是他们保存在栈区中的指向堆内存的地址倒是不一样的,因此两个对象不相等
引用类型的存储须要在内存的栈区和堆区共同完成,栈区保存变量标识符和指向堆内存的地址
假若有如下几个对象:
var person1 = {name:"change1"}; var person2 = {name:"change2"}; var person3 = {name:"change3"};
则这三个对象在内存中保存的状况以下图:
先看下如下代码:
var s1 = "helloworld"; var s2 = s1.substr(4);
上面咱们说到字符串是基本数据类型,不该该有方法,那为何这里s1能够调用substr()呢?
经过翻阅js权威指南第3.6章节和高级程序设计第5.6章节咱们得知,ECMAScript还提供了三个特殊的引用类型Boolean,String,Number.咱们称这三个特殊的引用类型为基本包装类型,也叫包装对象.
也就是说当读取string,boolean和number这三个基本数据类型的时候,后台就会建立一个对应的基本包装类型对象,从而让咱们可以调用一些方法来操做这些数据.
因此当第二行代码访问s1的时候,后台会自动完成下列操做:
正由于有第三步这个销毁的动做,因此你应该可以明白为何基本数据类型不能够添加属性和方法,这也正是基本装包类型和引用类型主要区别:对象的生存期.使用new操做符建立的引用类型的实例,在执行流离开当前做用域以前都是一直保存在内存中.而自动建立的基本包装类型的对象,则只存在于一行代码的执行瞬间,而后当即被销毁