前两天看到kraaas的一篇关于基本数据类型和引用类型区别的文章,觉得写的很好。一些知识点和理解,于是就有了下面几篇js基本数据类型:js基本数据类型包括:undefined,null,number,boolean,string。基本数据类型是按值访问的,也就是说我们可以操作变量1中存储的实际值。基本数据类型的值是不可变的。任何方法都不能改变基本类型的值,比如字符串:varname="change";name.substr();//hangconsole.log(name);//changevars="hello";s.toUpperCase()//HELLO;console.log(s)//hello通过这两个例子,我们会发现原来定义的变量名的值没有变化,但是调用substr()后返回了一个新的字符串和toUpperCase()方法,与最初定义的变量名无关。可能有人会有以下疑问,看代码:varname="change";name="change1";console.log(name)//change1看起来好像name的值"changed"。其实varname="change",这里的基本类型是string,也就是"change",这里的"change"是不能改变的,name只是一个指向"change"的指针,指针的指向可以改变,所以你可以name="change1"。此时,name指向“change1”。同样,“change1”也是不能改变的,也就是说,这里你认为的改变只是“指针指向改变”。这里的基本类型指的是“变化”,而不是名称。有必要区分清楚2.基本数据类型不能添加属性和方法varp="change";p.age=29;p.method=function(){console.log(name)};console.log(p.age)//undefinedconsole.log(p.method)//undefined通过了上面代码,我们知道基本类型不能添加属性和方法,也说明了基本类型是不可变的3.基本数据类型的赋值是简单的赋值。在上面创建一个新值并将值复制到分配给新变量的位置vara=10;varb=a;a++;console.log(a)//11console.log(b)//10在上面的代码中,a中保存的值为10。当a的值用于初始化b时,b中也保存了10的值。但是b中的10和a中的10是完全独立的。b中的值知道中间值的A副本。所以这两个变量可以参与任何操作,互不影响。如下图所示:4.基本数据类型的比较是值的比较varperson1='{}';varperson2='{}';console.log(person1==person2);//真5。基本数据类型存放在栈区。如果有以下基本类型变量:varname="jozo";varcity="guangzhou";varage=22;那么它的存储结构如下图所示:栈区包括变量的标识符和变量的值。Object,Array,Function,Data等1.可以改变引用类型的值varo={x:1};o.x=2;//通过修改对象属性值改变对象o.y=3;再次改变对象,给它添加一个属性vara=[1,2,3];a[0]=0;//改变数组的一个元素a[3]=4;//向数组添加一个元素2.引用类型可以添加属性和方法varperson={};person.name="改变";person.say=function(){alert("hello");}console.log(person.name)//changeconsole.log(person.say)//function(){alert("hello");}3.引用类型的赋值是对象引用先看下面代码:var一={};varb=a;a.name="change";console.log(a.name)//change;console.log(b.name)//changeb.age=29;console.log(a.age)//29console.log(b.age)//29当将一个变量的引用类型的值赋值给另一个变量时,该变量中存储的对象的值也会被复制,放在为新变量分配的空间中.变量中存储的引用类型是对象在堆内存中的地址,所以,不同于基本数据类型的简单赋值,这个值的副本实际上是一个指针,这个指针指向存储在堆内存中的一个对象堆内存。那么经过赋值操作后,两个变量都存储了同一个对象地址,这两个地址指向同一个对象。因此,改变其中的任何一个变量都会相互影响,它们的关系如下图所示:因此,引用类型的赋值实际上是对栈区中存储的对象的地址指针的赋值,所以两个变量指向对同一个对象,任何操作都会相互影响4.引用类型的比较是引用的比较varperson1={};varperson2={};console.log(person1==person2)//false为什么两个对象看起来一模一样,其实并不相等?因为引用类型的比较就是引用的比较,换句话说就是比较两个对象的栈区所指向的堆内存的地址是否相同。此时,虽然p1和p2看起来都是“{}”,但是它们存放在栈区指向堆内存的地址是不同的,所以两个对象不相等5.引用类型都存放在栈区和堆区。区一起完成,栈区保存变量标识符和指向堆内存的地址。如果有以下对象:varperson1={name:"change1"};varperson2={name:"change2"};varperson3={name:"change3"};那么这三个对象在内存中的存储如下:基本包装类型(包装对象):先看下面代码:vars1="helloworld";vars2=s1.substr(4);上面我们说了字符串是基本数据类型,不应该有方法,那么为什么s1可以在这里调用substr()呢?通过阅读权威js指南的3.6章和高级编程的5.6章,我们知道ECMAScript还提供了三种特殊的引用类型Boolean、String和Number。我们将这三种特殊的引用类型称为基本包装类型,也称为包装对象。也就是说,当string、boolean、number这三种基本数据类型被读取时,会在后台创建一个对应的基本wrapper类型对象,这样我们就可以调用一些方法来操作这些数据。所以当第二行代码访问到s1时,后台会自动完成如下操作:创建一个String类型的实例;//vars1=newString("helloworld");在实例上调用指定的方法;//变量s2=s1。子字符串(4);销毁这个实例;//s1=null;因为第三步的销毁动作,你应该能理解为什么基本数据类型不能添加属性和方法,这正是基本数据类型封装类型和引用类型的主要区别:对象的生命周期。由new运算符创建的引用类型的实例将保留在内存中,直到执行流离开当前范围。自动创建的基本包类型对象,只在执行一行代码的瞬间存在,然后立即销毁
