成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

一篇文章理解JS數(shù)據(jù)類型、深拷貝和淺拷貝

enda / 2549人閱讀

摘要:接下來(lái)我們進(jìn)入正片數(shù)據(jù)類型六種基本數(shù)據(jù)類型布爾值,和一個(gè)表明值的特殊關(guān)鍵字。一種數(shù)據(jù)類型,它的實(shí)例是唯一且不可改變的。在中是沒(méi)有方法是可以改變布爾值和數(shù)字的。參考資料深拷貝淺拷貝

前言

筆者最近整理了一些前端技術(shù)文章,如果有興趣可以參考這里:muwoo blogs。接下來(lái)我們進(jìn)入正片:

js 數(shù)據(jù)類型

六種 基本數(shù)據(jù)類型:

Boolean. 布爾值,true 和 false.

null. 一個(gè)表明 null 值的特殊關(guān)鍵字。 JavaScript 是大小寫(xiě)敏感的,因此 null 與 Null、NULL或其他變量完全不同。

undefined. 變量未定義時(shí)的屬性。

Number. 表示數(shù)字,例如: 42 或者 3.14159。

String. 表示字符串,例如:"Howdy"

Symbol ( 在 ECMAScript 6 中新添加的類型).。一種數(shù)據(jù)類型,它的實(shí)例是唯一且不可改變的。

以及 Object 對(duì)象引用數(shù)據(jù)類型

大多數(shù)情況下,我們可以通過(guò)typeof屬性來(lái)判斷。只不過(guò)有一些例外,比如:

var fn = new Function ("a", "b", "return a + b")

typeof fn // function

關(guān)于function屬不屬于js的數(shù)據(jù)類型,這里也有相關(guān)的討論JavaScript 里 Function 也算一種基本類型?

基本類型 和 引用數(shù)據(jù)類型 的相關(guān)區(qū)別 基本數(shù)據(jù)類型

我們來(lái)看一下 MDN 中對(duì)基本數(shù)據(jù)類型的一些定義:

除 Object 以外的所有類型都是不可變的(值本身無(wú)法被改變)。例如,與 C 語(yǔ)言不同,JavaScript 中字符串是不可變的(譯注:如,JavaScript 中對(duì)字符串的操作一定返回了一個(gè)新字符串,原始字符串并沒(méi)有被改變)。我們稱這些類型的值為“原始值”。
var a = "string"
a[0] = "a"
console.log(a)  // string

我們通常情況下都是對(duì)一個(gè)變量重新賦值,而不是改變基本數(shù)據(jù)類型的值。在 js 中是沒(méi)有方法是可以改變布爾值和數(shù)字的。倒是有很多操作字符串的方法,但是這些方法都是返回一個(gè)新的字符串,并沒(méi)有改變其原有的數(shù)據(jù)。比如:

獲取一個(gè)字符串的子串可通過(guò)選擇個(gè)別字母或者使用 String.substr().

兩個(gè)字符串的連接使用連接操作符 (+) 或者 String.concat().

引用數(shù)據(jù)類型

引用類型(object)是存放在堆內(nèi)存中的,變量實(shí)際上是一個(gè)存放在棧內(nèi)存的指針,這個(gè)指針指向堆內(nèi)存中的地址。每個(gè)空間大小不一樣,要根據(jù)情況開(kāi)進(jìn)行特定的分配,例如。

var person1 = {name:"jozo"};
var person2 = {name:"xiaom"};
var person3 = {name:"xiaoq"};

引用類型的值是可變的:

person1["name"] = "muwoo"

console.log(person1) // {name: "muwoo"}
傳值與傳址

了解了基本數(shù)據(jù)類型與引用類型的區(qū)別之后,我們就應(yīng)該能明白傳值與傳址的區(qū)別了。
在我們進(jìn)行賦值操作的時(shí)候,基本數(shù)據(jù)類型的賦值(=)是在內(nèi)存中新開(kāi)辟一段棧內(nèi)存,然后再把再將值賦值到新的棧中。例如:

var a = 10;
var b = a;

a ++ ;
console.log(a); // 11
console.log(b); // 10

所以說(shuō),基本類型的賦值的兩個(gè)變量是兩個(gè)獨(dú)立相互不影響的變量。

但是引用類型的賦值是傳址。只是改變指針的指向,例如,也就是說(shuō)引用類型的賦值是對(duì)象保存在棧中的地址的賦值,這樣的話兩個(gè)變量就指向同一個(gè)對(duì)象,因此兩者之間操作互相有影響。例如:

var a = {}; // a保存了一個(gè)空對(duì)象的實(shí)例
var b = a;  // a和b都指向了這個(gè)空對(duì)象

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

淺拷貝

先來(lái)看一段代碼的執(zhí)行:

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}}

這段代碼可以說(shuō)明賦值得到的對(duì)象 obj1 只是將指針改變,其引用的仍然是同一個(gè)對(duì)象,而淺拷貝得到的的 obj2 則是重新創(chuàng)建了新對(duì)象。但是,如果原對(duì)象obj中存在另一個(gè)對(duì)象,則不會(huì)對(duì)對(duì)象做另一次拷貝,而是只復(fù)制其變量對(duì)象的地址。這是因?yàn)闇\拷貝只復(fù)制一層對(duì)象的屬性,并不包括對(duì)象里面的為引用類型的數(shù)據(jù)。
對(duì)于數(shù)組,更長(zhǎng)見(jiàn)的淺拷貝方法便是slice(0)concat()
ES6 比較常見(jiàn)的淺拷貝方法便是 Object.assign

深拷貝

通過(guò)上面的這些說(shuō)明,相信你對(duì)深拷貝大致了解了是怎樣一個(gè)東西了:深拷貝是對(duì)對(duì)象以及對(duì)象的所有子對(duì)象進(jìn)行拷貝。那么如何實(shí)現(xiàn)這樣一個(gè)深拷貝呢?

1. JSON.parse(JSON.stringify(obj))

對(duì)于常規(guī)的對(duì)象,我們可以通過(guò)JSON.stringify來(lái)講對(duì)象轉(zhuǎn)成一個(gè)字符串,然后在用JSON.parse來(lái)為其分配另一個(gè)存儲(chǔ)地址,這樣可以解決內(nèi)存地址指向同一個(gè)的問(wèn)題:

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也存在一個(gè)問(wèn)題,JSON.parse() 和J SON.stringify()能正確處理的對(duì)象只有Number、String、Array等能夠被 json 表示的數(shù)據(jù)結(jié)構(gòu),因此函數(shù)這種不能被 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. 遍歷實(shí)現(xiàn)屬性復(fù)制

既然淺拷貝只能實(shí)現(xiàn)非object第一層屬性的復(fù)制,那么遇到object只需要通過(guò)遞歸實(shí)現(xiàn)淺拷貝其中內(nèi)部的屬性即可:

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]]

我們?cè)賮?lái)看一下 Zepto 中深拷貝的代碼:

    // 內(nèi)部方法:用戶合并一個(gè)或多個(gè)對(duì)象到第一個(gè)對(duì)象
    // 參數(shù):
    // target 目標(biāo)對(duì)象  對(duì)象都合并到target里
    // source 合并對(duì)象
    // deep 是否執(zhí)行深度合并
    function extend(target, source, deep) {
        for (key in source)
            if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
                // source[key] 是對(duì)象,而 target[key] 不是對(duì)象, 則 target[key] = {} 初始化一下,否則遞歸會(huì)出錯(cuò)的
                if (isPlainObject(source[key]) && !isPlainObject(target[key]))
                    target[key] = {}

                // source[key] 是數(shù)組,而 target[key] 不是數(shù)組,則 target[key] = [] 初始化一下,否則遞歸會(huì)出錯(cuò)的
                if (isArray(source[key]) && !isArray(target[key]))
                    target[key] = []
                // 執(zhí)行遞歸
                extend(target[key], source[key], deep)
            }
            // 不滿足以上條件,說(shuō)明 source[key] 是一般的值類型,直接賦值給 target 就是了
            else if (source[key] !== undefined) target[key] = source[key]
    }

內(nèi)部實(shí)現(xiàn)其實(shí)也是差不多。

參考資料

js 深拷貝 vs 淺拷貝

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/52403.html

相關(guān)文章

  • 文章理解JS數(shù)據(jù)類型、拷貝和淺拷貝

    摘要:接下來(lái)我們進(jìn)入正片數(shù)據(jù)類型六種基本數(shù)據(jù)類型布爾值,和一個(gè)表明值的特殊關(guān)鍵字。一種數(shù)據(jù)類型,它的實(shí)例是唯一且不可改變的。在中是沒(méi)有方法是可以改變布爾值和數(shù)字的。參考資料深拷貝淺拷貝 前言 筆者最近整理了一些前端技術(shù)文章,如果有興趣可以參考這里:muwoo blogs。接下來(lái)我們進(jìn)入正片: js 數(shù)據(jù)類型 六種 基本數(shù)據(jù)類型: Boolean. 布爾值,true 和 false. nu...

    EddieChan 評(píng)論0 收藏0
  • 文章徹底說(shuō)清JS拷貝/淺拷貝

    摘要:一篇文章徹底說(shuō)清的深拷貝淺拷貝這篇文章的受眾第一類業(yè)務(wù)需要急需知道如何深拷貝對(duì)象的開(kāi)發(fā)者。這篇文章分享的目的更多還是希望用一篇文章整理清楚深淺拷貝的含義遞歸實(shí)現(xiàn)思路以及小伙伴們?nèi)绻褂昧诉@種黑科技一定要清楚這樣寫(xiě)的優(yōu)缺點(diǎn)。 一篇文章徹底說(shuō)清JS的深拷貝and淺拷貝 這篇文章的受眾 第一類,業(yè)務(wù)需要,急需知道如何深拷貝JS對(duì)象的開(kāi)發(fā)者。 第二類,希望扎實(shí)JS基礎(chǔ),將來(lái)好去面試官前秀操作...

    J4ck_Chan 評(píng)論0 收藏0
  • 文章徹底說(shuō)清JS拷貝/淺拷貝

    摘要:一篇文章徹底說(shuō)清的深拷貝淺拷貝這篇文章的受眾第一類業(yè)務(wù)需要急需知道如何深拷貝對(duì)象的開(kāi)發(fā)者。這篇文章分享的目的更多還是希望用一篇文章整理清楚深淺拷貝的含義遞歸實(shí)現(xiàn)思路以及小伙伴們?nèi)绻褂昧诉@種黑科技一定要清楚這樣寫(xiě)的優(yōu)缺點(diǎn)。 一篇文章徹底說(shuō)清JS的深拷貝and淺拷貝 這篇文章的受眾 第一類,業(yè)務(wù)需要,急需知道如何深拷貝JS對(duì)象的開(kāi)發(fā)者。 第二類,希望扎實(shí)JS基礎(chǔ),將來(lái)好去面試官前秀操作...

    lakeside 評(píng)論0 收藏0
  • 文章徹底說(shuō)清JS拷貝/淺拷貝

    摘要:一篇文章徹底說(shuō)清的深拷貝淺拷貝這篇文章的受眾第一類業(yè)務(wù)需要急需知道如何深拷貝對(duì)象的開(kāi)發(fā)者。這篇文章分享的目的更多還是希望用一篇文章整理清楚深淺拷貝的含義遞歸實(shí)現(xiàn)思路以及小伙伴們?nèi)绻褂昧诉@種黑科技一定要清楚這樣寫(xiě)的優(yōu)缺點(diǎn)。 一篇文章徹底說(shuō)清JS的深拷貝and淺拷貝 這篇文章的受眾 第一類,業(yè)務(wù)需要,急需知道如何深拷貝JS對(duì)象的開(kāi)發(fā)者。 第二類,希望扎實(shí)JS基礎(chǔ),將來(lái)好去面試官前秀操作...

    big_cat 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<