摘要:接下來我們進入正片數據類型六種基本數據類型布爾值,和一個表明值的特殊關鍵字。一種數據類型,它的實例是唯一且不可改變的。在中是沒有方法是可以改變布爾值和數字的。參考資料深拷貝淺拷貝
前言
筆者最近整理了一些前端技術文章,如果有興趣可以參考這里:muwoo blogs。接下來我們進入正片:
js 數據類型六種 基本數據類型:
Boolean. 布爾值,true 和 false.
null. 一個表明 null 值的特殊關鍵字。 JavaScript 是大小寫敏感的,因此 null 與 Null、NULL或其他變量完全不同。
undefined. 變量未定義時的屬性。
Number. 表示數字,例如: 42 或者 3.14159。
String. 表示字符串,例如:"Howdy"
Symbol ( 在 ECMAScript 6 中新添加的類型).。一種數據類型,它的實例是唯一且不可改變的。
以及 Object 對象引用數據類型
大多數情況下,我們可以通過typeof屬性來判斷。只不過有一些例外,比如:
</>復制代碼
var fn = new Function ("a", "b", "return a + b")
typeof fn // function
關于function屬不屬于js的數據類型,這里也有相關的討論JavaScript 里 Function 也算一種基本類型?
基本類型 和 引用數據類型 的相關區別 基本數據類型我們來看一下 MDN 中對基本數據類型的一些定義:
</>復制代碼
除 Object 以外的所有類型都是不可變的(值本身無法被改變)。例如,與 C 語言不同,JavaScript 中字符串是不可變的(譯注:如,JavaScript 中對字符串的操作一定返回了一個新字符串,原始字符串并沒有被改變)。我們稱這些類型的值為“原始值”。
</>復制代碼
var a = "string"
a[0] = "a"
console.log(a) // string
我們通常情況下都是對一個變量重新賦值,而不是改變基本數據類型的值。在 js 中是沒有方法是可以改變布爾值和數字的。倒是有很多操作字符串的方法,但是這些方法都是返回一個新的字符串,并沒有改變其原有的數據。比如:
獲取一個字符串的子串可通過選擇個別字母或者使用 String.substr().
兩個字符串的連接使用連接操作符 (+) 或者 String.concat().
引用數據類型引用類型(object)是存放在堆內存中的,變量實際上是一個存放在棧內存的指針,這個指針指向堆內存中的地址。每個空間大小不一樣,要根據情況開進行特定的分配,例如。
</>復制代碼
var person1 = {name:"jozo"};
var person2 = {name:"xiaom"};
var person3 = {name:"xiaoq"};
引用類型的值是可變的:
</>復制代碼
person1["name"] = "muwoo"
console.log(person1) // {name: "muwoo"}
傳值與傳址
了解了基本數據類型與引用類型的區別之后,我們就應該能明白傳值與傳址的區別了。
在我們進行賦值操作的時候,基本數據類型的賦值(=)是在內存中新開辟一段棧內存,然后再把再將值賦值到新的棧中。例如:
</>復制代碼
var a = 10;
var b = a;
a ++ ;
console.log(a); // 11
console.log(b); // 10
所以說,基本類型的賦值的兩個變量是兩個獨立相互不影響的變量。
但是引用類型的賦值是傳址。只是改變指針的指向,例如,也就是說引用類型的賦值是對象保存在棧中的地址的賦值,這樣的話兩個變量就指向同一個對象,因此兩者之間操作互相有影響。例如:
</>復制代碼
var a = {}; // a保存了一個空對象的實例
var b = a; // a和b都指向了這個空對象
a.name = "jozo";
console.log(a.name); // "jozo"
console.log(b.name); // "jozo"
b.age = 22;
console.log(b.age);// 22
console.log(a.age);// 22
console.log(a == b);// true
淺拷貝
先來看一段代碼的執行:
</>復制代碼
var obj = {a: 1, b: {c: 2}}
var obj1 = obj
var obj2 = shallowCopy(obj);
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}
var obj3 = Object.assign({}, obj)
obj.a = 2
obj.b.c = 3
console.log(obj) // {a: 2, b: {c: 3}}
console.log(obj1) // {a: 2, b: {c: 3}}
console.log(obj2) // {a: 1, b: {c: 3}}
console.log(obj3) // {a: 1, b: {c: 3}}
這段代碼可以說明賦值得到的對象 obj1 只是將指針改變,其引用的仍然是同一個對象,而淺拷貝得到的的 obj2 則是重新創建了新對象。但是,如果原對象obj中存在另一個對象,則不會對對象做另一次拷貝,而是只復制其變量對象的地址。這是因為淺拷貝只復制一層對象的屬性,并不包括對象里面的為引用類型的數據。
對于數組,更長見的淺拷貝方法便是slice(0)和 concat()
ES6 比較常見的淺拷貝方法便是 Object.assign
通過上面的這些說明,相信你對深拷貝大致了解了是怎樣一個東西了:深拷貝是對對象以及對象的所有子對象進行拷貝。那么如何實現這樣一個深拷貝呢?
1. JSON.parse(JSON.stringify(obj))對于常規的對象,我們可以通過JSON.stringify來講對象轉成一個字符串,然后在用JSON.parse來為其分配另一個存儲地址,這樣可以解決內存地址指向同一個的問題:
</>復制代碼
var obj = {a: {b: 1}}
var copy = JSON.parse(JSON.stringify(obj))
obj.a.b = 2
console.log(obj) // {a: {b: 2}}
console.log(copy) // {a: {b: 1}}
但是 JSON.parse()、JSON.stringify也存在一個問題,JSON.parse() 和J SON.stringify()能正確處理的對象只有Number、String、Array等能夠被 json 表示的數據結構,因此函數這種不能被 json 表示的類型將不能被正確處理。
</>復制代碼
var target = {
a: 1,
b: 2,
hello: function() {
console.log("Hello, world!");
}
};
var copy = JSON.parse(JSON.stringify(target));
console.log(copy); // {a: 1, b: 2}
console.log(JSON.stringify(target)); // "{"a":1,"b":2}"
2. 遍歷實現屬性復制
既然淺拷貝只能實現非object第一層屬性的復制,那么遇到object只需要通過遞歸實現淺拷貝其中內部的屬性即可:
</>復制代碼
function extend (source) {
var target
if (typeof source === "object") {
target = Array.isArray(source) ? [] : {}
for (var key in source) {
if (source.hasOwnProperty(key)) {
if (typeof source[key] !== "object") {
target[key] = source[key]
} else {
target[key] = extend(source[key])
}
}
}
} else {
target = source
}
return target
}
var obj1 = {a: {b: 1}}
var cpObj1 = extend(obj1)
obj1.a.b = 2
console.log(cpObj1) // {a: {b: 1}}
var obj2 = [[1]]
var cpObj2 = extend(obj2)
obj2[0][0] = 2
console.log(cpObj2) // [[1]]
我們再來看一下 Zepto 中深拷貝的代碼:
</>復制代碼
// 內部方法:用戶合并一個或多個對象到第一個對象
// 參數:
// target 目標對象 對象都合并到target里
// source 合并對象
// deep 是否執行深度合并
function extend(target, source, deep) {
for (key in source)
if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
// source[key] 是對象,而 target[key] 不是對象, 則 target[key] = {} 初始化一下,否則遞歸會出錯的
if (isPlainObject(source[key]) && !isPlainObject(target[key]))
target[key] = {}
// source[key] 是數組,而 target[key] 不是數組,則 target[key] = [] 初始化一下,否則遞歸會出錯的
if (isArray(source[key]) && !isArray(target[key]))
target[key] = []
// 執行遞歸
extend(target[key], source[key], deep)
}
// 不滿足以上條件,說明 source[key] 是一般的值類型,直接賦值給 target 就是了
else if (source[key] !== undefined) target[key] = source[key]
}
內部實現其實也是差不多。
參考資料js 深拷貝 vs 淺拷貝
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/95240.html
摘要:接下來我們進入正片數據類型六種基本數據類型布爾值,和一個表明值的特殊關鍵字。一種數據類型,它的實例是唯一且不可改變的。在中是沒有方法是可以改變布爾值和數字的。參考資料深拷貝淺拷貝 前言 筆者最近整理了一些前端技術文章,如果有興趣可以參考這里:muwoo blogs。接下來我們進入正片: js 數據類型 六種 基本數據類型: Boolean. 布爾值,true 和 false. nu...
摘要:一篇文章徹底說清的深拷貝淺拷貝這篇文章的受眾第一類業務需要急需知道如何深拷貝對象的開發者。這篇文章分享的目的更多還是希望用一篇文章整理清楚深淺拷貝的含義遞歸實現思路以及小伙伴們如果使用了這種黑科技一定要清楚這樣寫的優缺點。 一篇文章徹底說清JS的深拷貝and淺拷貝 這篇文章的受眾 第一類,業務需要,急需知道如何深拷貝JS對象的開發者。 第二類,希望扎實JS基礎,將來好去面試官前秀操作...
摘要:一篇文章徹底說清的深拷貝淺拷貝這篇文章的受眾第一類業務需要急需知道如何深拷貝對象的開發者。這篇文章分享的目的更多還是希望用一篇文章整理清楚深淺拷貝的含義遞歸實現思路以及小伙伴們如果使用了這種黑科技一定要清楚這樣寫的優缺點。 一篇文章徹底說清JS的深拷貝and淺拷貝 這篇文章的受眾 第一類,業務需要,急需知道如何深拷貝JS對象的開發者。 第二類,希望扎實JS基礎,將來好去面試官前秀操作...
摘要:一篇文章徹底說清的深拷貝淺拷貝這篇文章的受眾第一類業務需要急需知道如何深拷貝對象的開發者。這篇文章分享的目的更多還是希望用一篇文章整理清楚深淺拷貝的含義遞歸實現思路以及小伙伴們如果使用了這種黑科技一定要清楚這樣寫的優缺點。 一篇文章徹底說清JS的深拷貝and淺拷貝 這篇文章的受眾 第一類,業務需要,急需知道如何深拷貝JS對象的開發者。 第二類,希望扎實JS基礎,將來好去面試官前秀操作...
閱讀 3440·2021-11-22 09:34
閱讀 1909·2019-08-30 12:53
閱讀 3502·2019-08-28 18:07
閱讀 2989·2019-08-27 10:55
閱讀 2967·2019-08-26 10:12
閱讀 3597·2019-08-23 18:21
閱讀 1349·2019-08-23 14:10
閱讀 1484·2019-08-23 13:04