前兩天看到kraaas
大神的關於基本資料類型和引用類型的區別的文章覺得寫得非常不錯,就想著在其基礎上加上我平常看到的一些知識點和理解,所以就有了以下的文章
js基本資料型別包括:undefined ,null,number,boolean,string.基本資料型別是按值存取的,就是說我們可以操作保存在變數中的實際的值
任何方法都無法改變一個基本類型的值,例如一個字串:
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″同樣不可以改變
#也就是說這裡你認為的改變只是“指標的指向改變”
這裡的基礎類型指的是”change”,而不是name,要區分清楚
var p = "change"; p.age = 29; p.method = function(){console.log(name)}; console.log(p.age)//undefined console.log(p.method)//undefined
透過上面的程式碼,我們知道不能為基本型別新增屬性和方法,也再次說明基本型別是不可變的
如果從一個變數向另一個變數賦值基本型別的值,會在變數物件上建立一個新值,然後把該值複製到為新變數指派的位置上
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;
那麼它的儲存結構如下圖:
堆疊區包含了變數的識別碼和變數的值
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當從一個變數向另一個變數賦值引用類型的值時,同樣也會將儲存在變數中的物件的值複製一份放到為新變數分配的空間中.引用型別保存在變數中的是物件在堆記憶體中的位址,所以,與基本資料類型的簡單賦值不同,這個值的副本實際上是一個指針,而這個指針指向存儲在堆內存的一個對象.那麼賦值操作後,兩個變量都保存了同一個對像地址,而這兩個地址指向了同一個物件.因此,改變其中任何一個變量,都會互相影響他們的關係如下圖:
##因此,引用類型的賦值其實是物件保存在堆疊區位址指標的賦值,所以兩個變數指向同一個對象,任何的操作都會互相影響。
4. 引用類型的比較是引用的比較
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的时候,后台会自动完成下列操作:
创建String类型的一个实例;// var s1 = new String(“helloworld”);
在实例上调用指定方法;// var s2 = s1.substr(4);
销毁这个实例;// s1 = null;
正因为有第三步这个销毁的动作,所以你应该能够明白为什么基本数据类型不可以添加属性和方法,这也正是基本装包类型和引用类型主要区别:对象的生存期.使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都是一直保存在内存中.而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。
以上就是JavaScript 基本数据类型和引用类型的区别详解 的内容,更多相关内容请关注PHP中文网(www.php.cn)!
相关文章: