JavaScript引用數(shù)據(jù)類型(對(duì)象類型)和原始(基本)數(shù)據(jù)類型特點(diǎn)比較
為講解JavaScript引用數(shù)據(jù)類型(對(duì)象類型)和原始(基本)數(shù)據(jù)類型特點(diǎn)比較,需要先回顧JavaScript數(shù)據(jù)類型有哪些?
一)原始(primitive:原始、基本)數(shù)據(jù)類型,也稱為原始值(primitive value),包括:
1.布爾值(Boolean),其字面值只有兩個(gè),分別是true和false。
2.null,Null類型只有一個(gè)唯一的字面值null, null 值的特殊關(guān)鍵字。JavaScript 是大小寫敏感的,因此 null 與 Null、NULL或變體完全不同。
3.undefined,Undefined類型只有一個(gè)唯一的字面值undefined,undefined 表示變量未賦值時(shí)的屬性。而undefined是JavaScript中的一個(gè)全局變量,即掛載在window對(duì)象上的一個(gè)變量,并不是關(guān)鍵字。
4.數(shù)字(Number),整數(shù)或浮點(diǎn)數(shù),例如: 42 或者 3.14159。
5.任意精度的整數(shù)(BigInt),可以安全地存儲(chǔ)和操作大整數(shù)。?ECMAScript 2020?引入了一個(gè)新的原始數(shù)據(jù)類型BigInt,用于表示任意精度的整數(shù)。在之前的版本中,JavaScript只能表示有限范圍的整數(shù),超出范圍的整數(shù)會(huì)被轉(zhuǎn)換為特殊的Infinity值。
6.字符串(String),字符串是一串表示文本值的字符序列,例如:"Howdy"。
7.符號(hào)(Symbol,在 ECMAScript 2015 / ES6 中新添加的類型)。一種實(shí)例是唯一且不可改變的數(shù)據(jù)類型。
二)對(duì)象(object)類型,是一種非原始(non-primitive)數(shù)據(jù)類型,也稱為引用值(reference value),用于更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。JavaScript中的對(duì)象類型包括:
1、普通對(duì)象(Plain objects):是指用戶自定義的對(duì)象類型。這些對(duì)象通常是通過使用構(gòu)造函數(shù)或類來定義的。在JavaScript中,有多種方式可以創(chuàng)建對(duì)象。在ES6及以后的版本中,JavaScript引入了類(class),這是一種創(chuàng)建和定義對(duì)象的新方法。
2、數(shù)組(Arrays):例如let arr = [1, 2, 3]; 數(shù)組對(duì)象有一些特殊的屬性和方法,如length、push、pop等。
3、函數(shù)(Functions):函數(shù)也是對(duì)象,它們可以有屬性和方法。例如:
function sayHello() {
? console.log('Hello');
}
sayHello.myProperty = 'This is a property of the function.';
4、日期(Dates):例如let date = new Date();
5、正則表達(dá)式(RegExp,Regular expressions):例如let regex = /ab+c/;
6、其他內(nèi)置對(duì)象,如Math,Set,Map等。
JavaScript原始(基本)數(shù)據(jù)類型和引用數(shù)據(jù)類型(對(duì)象類型)特點(diǎn)差別:
☆原始(基本)數(shù)據(jù)類型只能表示一個(gè)簡單的值,不能添加、修改和刪除屬性。引用數(shù)據(jù)類型可以包含多個(gè)鍵值對(duì),形成復(fù)雜的數(shù)據(jù)結(jié)構(gòu),可以動(dòng)態(tài)地添加、修改和刪除屬性。
?原始(基本)數(shù)據(jù)類型只能表示一個(gè)簡單的值,比如字符串、數(shù)字、布爾值等。它們不能添加、修改和刪除屬性。
例如:
let num = 5;
num = 10; // 修改變量的值
console.log(num); // 10
let str = "Hello";
str.length = 5; // 添加屬性
console.log(str.length); // undefined
在這個(gè)例子中,我們可以修改原始數(shù)據(jù)類型的變量的值,但不能添加屬性。即使我們嘗試添加屬性,也不會(huì)對(duì)原始數(shù)據(jù)類型的值產(chǎn)生影響。因?yàn)樵紨?shù)據(jù)類型的值是不可變的,它們沒有屬性可以修改或刪除。
引用數(shù)據(jù)類型可以包含多個(gè)鍵值對(duì),形成復(fù)雜的數(shù)據(jù)結(jié)構(gòu),比如對(duì)象和數(shù)組。你可以動(dòng)態(tài)地添加、修改和刪除屬性或元素。
例如:
let person = {
name: "John",
age: 30,
hobbies: ["reading", "coding"]
};
person.name = "Jane"; // 修改屬性值
person.gender = "female"; // 添加新屬性
delete person.age; // 刪除屬性
console.log(person); // { name: "Jane", hobbies: ["reading", "coding"], gender: "female" }
在這個(gè)例子中,我們有一個(gè)person對(duì)象,它包含了name、age和hobbies等屬性。我們可以通過修改屬性值、添加新屬性或刪除屬性來動(dòng)態(tài)地改變對(duì)象的結(jié)構(gòu)。
☆ 原始(基本)數(shù)據(jù)類型的值是不可變的,引用數(shù)據(jù)類型的值是可變的。
原始(基本)數(shù)據(jù)類型的值是不可變的,意味著你不能直接修改它們的值。當(dāng)你嘗試修改原始數(shù)據(jù)類型的變量值時(shí),實(shí)際上是創(chuàng)建了一個(gè)新的值,并將其賦給變量。
例如:
let num = 5;
num = 10;
console.log(num); // 10
在這個(gè)例子中,我們將num的值從5修改為10,但實(shí)際上是創(chuàng)建了一個(gè)新的值10,并將其賦給num變量。
引用數(shù)據(jù)類型的值是可變的,意味著你可以修改它們的屬性或元素。這是因?yàn)橐脭?shù)據(jù)類型的值實(shí)際上是存儲(chǔ)在內(nèi)存中的對(duì)象,變量只是指向這個(gè)對(duì)象的引用。當(dāng)你修改引用數(shù)據(jù)類型的值時(shí),實(shí)際上是在修改對(duì)象本身,而不是修改變量的值。
例如:
let obj = { name: "John" };
obj.name = "Jane";
console.log(obj); // { name: "Jane" }
在這個(gè)例子中,我們修改了obj對(duì)象的name屬性的值,這是因?yàn)閛bj是一個(gè)引用數(shù)據(jù)類型,它指向的對(duì)象是可變的。
這種不可變性的特性使得原始數(shù)據(jù)類型在處理簡單的數(shù)據(jù)時(shí)更加方便和可靠,而引用數(shù)據(jù)類型則更適合處理復(fù)雜的數(shù)據(jù)結(jié)構(gòu)和對(duì)象。
☆?變量賦值方面,原始(基本)數(shù)據(jù)類型的變量賦值是值的復(fù)制,而引用數(shù)據(jù)類型(對(duì)象類型)的變量賦值是引用的復(fù)制。
當(dāng)執(zhí)行到變量賦值語句時(shí),JavaScript引擎會(huì)將賦值操作的右側(cè)表達(dá)式計(jì)算出一個(gè)值,并將該值賦給變量。賦值操作可以使用賦值運(yùn)算符 =,也可以使用其他賦值運(yùn)算符(如 +=、-= 等)。
變量賦值是一個(gè)按值傳遞的過程。對(duì)于基本數(shù)據(jù)類型(如數(shù)字、字符串、布爾值等),賦操作會(huì)將值復(fù)制給變量。而對(duì)于引用數(shù)據(jù)類型(如對(duì)象、數(shù)組等),賦值操作會(huì)將引用(指向?qū)ο蟮膬?nèi)存地址)復(fù)制給變量,而不是復(fù)制對(duì)象本身。這意味著,當(dāng)你修改一個(gè)引用類型的變量時(shí),實(shí)際上是修改了引用所指向的對(duì)象。
對(duì)于原始類型,變量賦值是通過將一個(gè)值復(fù)制給另一個(gè)變量來完成的。這意味著當(dāng)你將一個(gè)原始數(shù)據(jù)類型的變量賦值給另一個(gè)變量時(shí),實(shí)際上是將原始值復(fù)制到了新的變量中。這兩個(gè)變量是完全獨(dú)立的,修改其中一個(gè)變量的值不會(huì)影響另一個(gè)變量。
例如:
let a = 5.1;
let b = a;
b = 10.2;
console.log(a); // 輸出 5.1
console.log(b); // 輸出 10.2
當(dāng)把一個(gè)原始變量的值賦給另一個(gè)原始變量時(shí),只是把棧中的內(nèi)容復(fù)制給另一個(gè)原始變量,此時(shí)這兩個(gè)變量互不影響——其實(shí)在內(nèi)存中是兩個(gè)地址,是互相獨(dú)立的存在,當(dāng)一個(gè)變量值改變時(shí),另一個(gè)變量不會(huì)因此而發(fā)生任何變化。圖解如下:
【圖中的紅色?,表示5.1這個(gè)值不再被變量a引用,若一個(gè)值不再被任何變量引用,可以被垃圾回收器標(biāo)記為可回收的,具體的垃圾回收時(shí)間是由JavaScript引擎決定的?!?/p>
對(duì)于引用數(shù)據(jù)類型,變量賦值是通過將引用復(fù)制給另一個(gè)變量來完成的。引用是指向存儲(chǔ)在內(nèi)存中的對(duì)象的地址。當(dāng)你將一個(gè)引用數(shù)據(jù)類型的變量賦值給另一個(gè)變量時(shí),實(shí)際上是將引用復(fù)制到了新的變量中。這兩個(gè)變量指向同一個(gè)對(duì)象,修改其中一個(gè)變量的屬性會(huì)影響另一個(gè)變量。
例如:
let obj1 = { name: 'Alice' };
let obj2 = obj1;
obj2.name = 'Bob';
console.log(obj1.name); // 輸出 'Bob'
console.log(obj2.name); // 輸出 'Bob'
需要注意的是,當(dāng)你修改引用數(shù)據(jù)類型的屬性時(shí),實(shí)際上是修改了對(duì)象本身,而不是變量。因此,所有指向該對(duì)象的變量都會(huì)反映出這個(gè)修改。圖解如下:
☆??參數(shù)傳遞方面,在 JavaScript中,參數(shù)傳遞方式是按值傳遞——傳遞的是副本。具體說來:1)當(dāng)將一個(gè)原始(基本)數(shù)據(jù)類型(如數(shù)字、字符串、布爾值等)作為參數(shù)傳遞給函數(shù)時(shí),實(shí)際上是將該值的一個(gè)副本傳遞給函數(shù)——將實(shí)參值復(fù)制給形參,實(shí)參和形參相互獨(dú)立互不干擾。函數(shù)內(nèi)部對(duì)該副本的修改不會(huì)影響到原始的值。2)當(dāng)將一個(gè)引用數(shù)據(jù)類型(對(duì)象類型)(如對(duì)象、數(shù)組等)作為參數(shù)傳遞給函數(shù)時(shí),傳遞的是該對(duì)象的引用(地址)的副本——將實(shí)參引用的地址值復(fù)制給形參,形參和實(shí)參指向同一個(gè)對(duì)象的地址,改變形參所指向的對(duì)象的屬性將影響實(shí)參所指向的對(duì)象。需要注意,在引用類型的參數(shù)傳遞中,并不會(huì)改變形參的值(即引用的地址),而是通過形參改變它所指向的對(duì)象的屬性。
當(dāng)傳遞原始數(shù)據(jù)類型時(shí),實(shí)際上是將原始值的副本傳遞給了函數(shù)或其他變量。這意味著函數(shù)或其他變量操作的是原始值的副本,而不是原始值本身。
這種傳遞方式使得函數(shù)內(nèi)部對(duì)原始值的修改不會(huì)影響到函數(shù)外部的變量,因?yàn)楹瘮?shù)內(nèi)部操作的是原始值的副本,而不是原始值本身。
例如:
function addTen(num) { // num 是一個(gè)局部變量
num += 10;
return num;
}
let count = 20;
let result = addTen(count);
console.log(count); // 20,沒有變化
console.log(result); // 30
解析如下:
此例展示了在 JavaScript 中傳遞變量的值的方式。
例中定義了一個(gè)函數(shù) addTen,它接受一個(gè)參數(shù) num。
在此主要關(guān)注變量情況:
首先,定義了一個(gè)變量 count,并賦值為 20。
接下來,調(diào)用 addTen 函數(shù),并將 count 作為參數(shù)傳遞進(jìn)去。這里需要注意的是,雖然 count 的值是 20,但是在函數(shù)中傳遞的是 count 的值的副本,而不是 count 本身。
在函數(shù)內(nèi)部,num 的值被增加了 10,變成了 30。然后,函數(shù)返回了這個(gè)新的值,并將其賦給了變量 result。
最后,通過 console.log 打印了 count 和 result 的值。由于在函數(shù)中傳遞的是 count 的值的副本,所以 count 的值沒有發(fā)生變化,仍然是 20。而 result 的值是函數(shù)返回的新值,即 30。圖解如下:
當(dāng)傳遞引用數(shù)據(jù)類型時(shí),實(shí)際上是將引用的地址傳遞給了函數(shù)。這意味著函數(shù)可以通過引用來訪問和修改原始對(duì)象。引用是指向存儲(chǔ)在內(nèi)存中的對(duì)象的地址,所以傳遞引用時(shí),傳遞的是指向?qū)ο蟮闹羔?,而不是?duì)象本身的實(shí)際值。
這種傳遞方式使得我們可以在函數(shù)內(nèi)部修改原始對(duì)象,并且這些修改會(huì)在函數(shù)外部可見。因?yàn)楹瘮?shù)和外部變量都指向同一個(gè)對(duì)象,所以對(duì)對(duì)象的修改會(huì)影響到所有引用該對(duì)象的變量。
例如:
function changeName(obj) {
obj.name = 'Bob';
}
let person = { name: 'Alice' };
console.log(person.name); // 輸出 'Alice'
changeName(person);
console.log(person.name); // 輸出 'Bob'
解析如下:
此例展示了在 JavaScript 中傳遞對(duì)象的引用的方式。
例中定義了一個(gè)函數(shù) changeName,它接受一個(gè)參數(shù) obj。
在此主要關(guān)注變量情況:
首先,定義了一個(gè)對(duì)象 person,并賦值為 { name: 'Alice' }。這個(gè)對(duì)象有一個(gè) name 屬性,其初始值為 ‘Alice’。
接下來,通過 console.log 打印了 person.name 的值,即 ‘Alice’。
然后,調(diào)用 changeName 函數(shù),并將 person 對(duì)象作為參數(shù)傳遞進(jìn)去。這里需要注意的是,雖然 person 是一個(gè)對(duì)象,但是在函數(shù)中傳遞的是 person 對(duì)象的引用,而不是對(duì)象本身的副本。
在函數(shù)內(nèi)部,通過修改 obj 的 name 屬性,將其值改為 ‘Bob’。由于 obj 是 person 對(duì)象的引用,所以這個(gè)修改也會(huì)影響到 person 對(duì)象本身。
最后,通過 console.log 打印了 person.name 的值,即 ‘Bob’。由于在函數(shù)中修改了 person 對(duì)象的 name 屬性,所以 person.name 的值變成了 ‘Bob’。圖解如下:
總結(jié)之,傳遞引用時(shí),傳遞的是引用的地址,而不是實(shí)際的值。傳遞原始數(shù)據(jù)類型時(shí),傳遞的是實(shí)際的值的副本。這種差異導(dǎo)致了在函數(shù)內(nèi)部對(duì)引用數(shù)據(jù)類型的修改會(huì)影響到函數(shù)外部的變量,而對(duì)原始數(shù)據(jù)類型的修改不會(huì)影響到函數(shù)外部的變量。
☆ 數(shù)據(jù)比較方面,原始(基本)數(shù)據(jù)類型的比較是對(duì)值的比較,引用數(shù)據(jù)類型的比較是對(duì)內(nèi)存地址的比較。
對(duì)于原始(基本)數(shù)據(jù)類型的比較,是對(duì)值的比較。例如:
let num1 = 5;
let num2 = 5;
console.log(num1 === num2); // true
因?yàn)閚um1和num2的值相同,所以比較結(jié)果為true。
引用數(shù)據(jù)類型的比較是對(duì)內(nèi)存地址的比較,而不是對(duì)值的比較。這意味著當(dāng)你比較兩個(gè)引用數(shù)據(jù)類型的變量時(shí),實(shí)際上是在比較它們是否指向同一個(gè)內(nèi)存地址。例如:
let obj1 = { name: "John" };
let obj2 = { name: "John" };
console.log(obj1 === obj2); // false
盡管obj1和obj2的屬性值相同,但它們指向的是不同的內(nèi)存地址,所以比較結(jié)果為false。
補(bǔ)充、關(guān)于“JavaScript(JS)參數(shù)傳遞按值傳遞” MDN Web Docs說法
Arguments are always passed by value and never passed by reference. This means that if a function reassigns a parameter, the value won't change outside the function. More precisely, object arguments are passed by sharing, which means if the object's properties are mutated, the change will impact the outside of the function.
【選自https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions 】
譯文:實(shí)參總是按值傳遞,而不是按引用傳遞。這意味著,如果函數(shù)重新賦值一個(gè)參數(shù),該值在函數(shù)外部不會(huì)改變。更準(zhǔn)確地說,對(duì)象參數(shù)是通過共享傳遞的,這意味著如果對(duì)象的屬性發(fā)生了變化,那么這種變化將影響函數(shù)的外部。
解析一下:
JS調(diào)用函數(shù)時(shí),參數(shù)本質(zhì)上是按值傳遞給函數(shù)的。傳遞給函數(shù)的值被稱為函數(shù)的實(shí)參(值傳遞),對(duì)應(yīng)位置的函數(shù)參數(shù)名叫作形參。如果實(shí)參是一個(gè)包含原始值 (數(shù)字,字符串,布爾值) 的變量,則就算函數(shù)在內(nèi)部改變了對(duì)應(yīng)形參的值,返回后,該實(shí)參變量的值也不會(huì)改變。如果實(shí)參是一個(gè)對(duì)象引用,則對(duì)應(yīng)形參會(huì)和該實(shí)參指向同一個(gè)對(duì)象。假如函數(shù)在內(nèi)部改變了對(duì)應(yīng)形參的值,返回后,實(shí)參指向的對(duì)象的值也會(huì)改變。
附錄、
JavaScript中的可變(Mutable)、不可變(Immutable)和變量的賦值介紹 https://blog.csdn.net/cnds123/article/details/134036700
多種(C++、Java、JavaScript、Python)編程語言參數(shù)傳遞方式介紹 https://blog.csdn.net/cnds123/article/details/132981086文章來源:http://www.zghlxwxcb.cn/news/detail-743099.html
ECMAScript 中變量的復(fù)制,以及函數(shù)的參數(shù)傳遞
https://juejin.cn/post/6953878356836384805文章來源地址http://www.zghlxwxcb.cn/news/detail-743099.html
到了這里,關(guān)于JavaScript引用數(shù)據(jù)類型(對(duì)象類型)和原始(基本)數(shù)據(jù)類型特點(diǎn)比較的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!