亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

JS類型判斷、對(duì)象克隆、數(shù)組克隆

dreamtecher / 1389人閱讀

摘要:對(duì)象克隆我們經(jīng)常會(huì)用到一個(gè)對(duì)象去做一些事情,可能有時(shí)候我們不想改變?cè)械臄?shù)據(jù)。如果是對(duì)象接著遞歸復(fù)制判斷是對(duì)象還是數(shù)組其實(shí)這還不是最終的深克隆,因?yàn)檫@一個(gè)也有它自己的問題,但是面對(duì)一般的情況應(yīng)該沒問題,跟高級(jí)的用法請(qǐng)自行學(xué)習(xí)。

類型判斷

我們先說一下JS的數(shù)據(jù)類型,我們一般說JS有六大數(shù)據(jù)類型(ES6以前)分別是:

基本數(shù)據(jù)類型

Number

String

Boolean

null

undefined

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

object

在ES6中新增了Symbol數(shù)據(jù)類型。

有時(shí)我們需要知道數(shù)據(jù)的類型其判斷一些事情,我們經(jīng)常會(huì)用typeof去判斷數(shù)據(jù)類型。

那么typeof能判斷什么類型呢?

Number

String

Boolean

object

undefined

function

就這幾個(gè)數(shù)據(jù)類型,但這些我們夠用嗎?或者說準(zhǔn)確嗎?

我們沒有看到null那么他是什么類型呢?我們用typeof null發(fā)現(xiàn)它是object,是不是很奇怪,其實(shí)這是一個(gè)bug,但是這個(gè)bug是能修復(fù)的但是不能修復(fù),因?yàn)閚ull一般是用來表示一個(gè)對(duì)象是空的,有時(shí)我們用null來取消事件,我理解的它好像是一個(gè)占位符,表示這個(gè)對(duì)象是空的。那為什么不能修復(fù)呢?因?yàn)樾迯?fù)它好說,但是修復(fù)了它會(huì)帶來許多麻煩。

專業(yè)點(diǎn)說就是:不同的對(duì)象在底層都是用二進(jìn)制來表示,在JS中二進(jìn)制前三位都是0的就會(huì)判斷為object類型,因?yàn)閚ull全是0所以會(huì)判斷null也是object類型。

我們來看一下typeof判斷的情況。

console.log(typeof(1)); //number
console.log(typeof("1")); // string
console.log(typeof(true)); // boolean
console.log(typeof({})); // object
console.log(typeof(function (){})); // function
console.log(typeof(null)); // object
console.log(typeof(undefined)); // undefined

當(dāng)我們想判斷一個(gè)對(duì)象那個(gè)是不是null或者是不是Date、RegExp等類型時(shí)會(huì)怎么樣呢?我們發(fā)現(xiàn)都是object,那我們有沒有辦法區(qū)分他們呢?
在這之前我先介紹一下Object.prototype.toString這個(gè)方法,我相信大家不陌生吧。它也能判斷數(shù)據(jù)類型,但是是這樣的。

console.log(Object.prototype.toString.call(1)); 
console.log(Object.prototype.toString.call("1"));
console.log(Object.prototype.toString.call(true));
console.log(Object.prototype.toString.call({})); 
console.log(Object.prototype.toString.call(function (){}));
console.log(Object.prototype.toString.call(null));
console.log(Object.prototype.toString.call(undefined)); 
console.log(Object.prototype.toString.call(new RegExp())); 
console.log(Object.prototype.toString.call(new Date()));
[object Number]
[object String]
[object Boolean]
[object Object]
[object Function]
[object Null]
[object Undefined]
[object RegExp]
[object Date]

我們發(fā)現(xiàn)它比typeof高級(jí)點(diǎn),能分辨的更準(zhǔn)確,但是格式好像不是我們要的。

接下來進(jìn)入主題,直接上代碼。

//首先定義好數(shù)據(jù)類型。
let types = {
    "[object Object]": "Object",
    "[object RegExp]": "RegExp",
    "[object Date]": "Date"
};
function type(regs) {
    let result = typeof(regs); // 先獲取傳過來的參數(shù)
    // 如果是對(duì)象在進(jìn)行判斷,不是則返回。
    if(result === "object"){
        if(regs === null){
            return "null";
        }else{
            return types[Object.prototype.toString.call(regs)];
        }
    }else{
        return result;
    }
}
console.log(type(1)); //number
console.log(type("1")); // string
console.log(type(true)); // boolean
console.log(type({})); // object
console.log(type(function (){})); // function
console.log(type(null)); // null
console.log(type(undefined)); // undefined
console.log(type(new RegExp())); //RegExp
console.log(type(new Date())); //Date

對(duì)象克隆

我們經(jīng)常會(huì)用到一個(gè)對(duì)象去做一些事情,可能有時(shí)候我們不想改變?cè)械臄?shù)據(jù)。,時(shí)候我們就需要對(duì)象克隆了,你可能簡(jiǎn)單的以為就是 = 就行了,那我們來看一看。

let obj = {
    a: 1
}
let obj2 = obj;
console.log(obj); //{a: 1}
console.log(obj2); //{a: 1}

我們看到復(fù)制過來了,這樣我們就可以隨便使用了。那我們來修改一下obj看看。

obj.a = 2;
console.log(obj); //{a: 2}
console.log(obj2); //{a: 2}

發(fā)現(xiàn)都變成了{a: 2},是不是很奇怪。因?yàn)閷?duì)象是引用類型的,他們賦值其實(shí)是賦的地址值,就是他們指向同一個(gè)地方,那么我們應(yīng)該怎么做呢?你應(yīng)該知道怎么遍歷對(duì)象,我們就把它遍歷一遍再?gòu)?fù)制??创a

let obj = {
    a: 1
}
function clone(obj) {
        let a = {};
        for(let o in obj){
            a[o] = obj[o]
        }
        return a;
}
let obj2 = clone(obj);
console.log(obj); //{a: 1}
console.log(obj2); //{a: 1}
obj.a = 2;
console.log(obj); //{a: 2}
console.log(obj2); //{a: 1}

沒有改變,看來我們成功了,那這篇文章就到這了。呵呵,其實(shí)遠(yuǎn)沒有,我們來看一下有沒有什么問題。

當(dāng)里面的數(shù)據(jù)為引用類型時(shí):

let obj = {
    a: {
        b: 1
    },
    c: 3
}
function clone(obj) {
        let a = {};
        for(let o in obj){
            a[o] = obj[o]
        }
        return a;
}
let obj2 = clone(obj);
console.log(obj);
console.log(obj2);
obj.a .b = 2;
console.log(obj);
console.log(obj2);

我們發(fā)現(xiàn)
又出問題了。

如果你知道for...in你就會(huì)知道它的另一個(gè)錯(cuò)誤。就是它會(huì)遍歷它原型上的可枚舉屬性和非Symbol的屬性。那么我們?cè)趺锤纳埔幌履兀楷F(xiàn)在介紹一下hasOwnProperty這個(gè)屬性,它就是判斷自身有沒有這個(gè)屬性,而不會(huì)去原型上找。

function clone(obj) {
    let a = {};
    for(let o in obj){
        if(obj.hasOwnProperty(o)){
            a[o] = obj[o];
        }
    }
    return a;
}

這個(gè)問題解決了,就差上一個(gè)了,我們接著用判斷數(shù)據(jù)的類型來判斷是否還需要復(fù)制的方法解決上一個(gè)問題。

let obj = {
    a: {
        b: 1,
        d: {
            e:[{f: 2}],
            g: {
                h:{
                    l: 5
                }
            }
        }
    },
    c: 3
}

function deepClone(origin, target) {
        let tar = target || {},
            arr = "[object Array]",
            str =  Object.prototype.toString;
        for(let o in origin){
            if(origin.hasOwnProperty(o)){
                // 如果是對(duì)象接著遞歸復(fù)制
                if(typeof origin[o] === "object"){ 
                // 判斷是對(duì)象還是數(shù)組
                        tar[o] = str.call(origin[o]) === arr ?  [] : {};
                        deepClone(origin[o], tar[o]);
                }else{
                    tar[o] = origin[o]; 
                }
            }
        }
        return tar;
}
let obj2 = deepClone(obj, {});
console.log(obj);
console.log(obj2);
obj.a.d.g.h.l = 6;
console.log(obj.a.d.g.h.l); //6
console.log(obj2.a.d.g.h.l); //5

其實(shí)這還不是最終的深克隆,因?yàn)檫@一個(gè)也有它自己的問題,但是面對(duì)一般的情況應(yīng)該沒問題,跟高級(jí)的用法請(qǐng)自行學(xué)習(xí)。

模擬實(shí)現(xiàn)JQ的$.extend()方法(只是粗略的寫了一下,如有錯(cuò)誤歡迎指出):

function extend() {
    let origin, // 要拷貝的源
         target = arguments[0], // 獲取第一個(gè)參數(shù)
         isDeepClone = false; // 是否深拷貝
         length = arguments.length, //拷貝的個(gè)數(shù)
         arr = "[object Array]",
        str =  Object.prototype.toString,
         i = 0;
    if(typeof target === "boolean"){
        isDeepClone = target;
        i ++;
        target = arguments[i]; //獲取目標(biāo)元素
    }
    //防止循環(huán)引用
    if(origin === target){
        return;
    }
    // 兼容function
    if(typeof target !== "object" && typeof target !== "function" ){
        target = {};
    }
    for ( ; i < length; i++) {
        origin = arguments[i];
        for(let o in origin){
            if(origin.hasOwnProperty(o)){
                if(origin[o] === "object"){
                        if(isDeepClone){
                            target[o] = str.call(origin[o]) === arr ? [] : {};
                            extend(true, target[o], origin[o]);
                        }
                }else{
                    target[o] = origin[o];
                }
            }
        }
    }
    return target;
}

補(bǔ)充:其實(shí)不止這一種深克隆的方法,不如我們處理數(shù)據(jù)最常使用的JSON

let obj = {
    a: {
        b: function (argument) {

        },
        d: {
            e:[{f: 2}],
            g: {
                h:{
                    l: 5
                }
            }
        }
    },
    c: 3
}
let r = JSON.stringify(obj);
r = JSON.parse(r);
obj.a.d.g.h.l = 6;
console.log(r.a.d.g.h.l); // 5

也是可以的,我們輸出一下r看看。

有沒有發(fā)現(xiàn)少了什么?對(duì),就是function,它不僅不能復(fù)制function還有undefined也不行,還有別的自己查一下吧。

3.數(shù)組克隆

有了上面的鋪墊,我們知道數(shù)組也是引用類型,就不能簡(jiǎn)單的等于來復(fù)制。

concat

let arr = [8,5,6,6,8];
let arr2 = arr.concat();
arr2[3] = 1;
console.log(arr); //[8, 5, 6, 6, 8]
console.log(arr2); //[8, 5, 6, 1, 8]

可以復(fù)制成功,那么引用類型呢?

let arr = [8,{a: 1},6,6,8];
let arr2 = arr.concat();
arr2[1].a = 2;
console.log(arr); 
console.log(arr2);

還有我們常用的slice也是一樣

let arr = [8,{a: 1},6,6,8];
let arr2 = arr.slice();
arr2[1].a = 2;
arr2[2] = 2;
console.log(arr); 
console.log(arr2);

還有一些別的方法,我就不一一列舉了,這些都是淺復(fù)制。

如果想深度克隆數(shù)組,也可以使用上面介紹的使用JSON也是可以的。

let arr = [8,{a: 1},6,6,8];
let arr2 = JSON.parse( JSON.stringify(arr) );
arr2[1].a = 2;
arr2[2] = 2;
console.log(arr); 
console.log(arr2);

目前想到的就這些,總感覺拉下了什么,如果我想起來了我會(huì)繼續(xù)補(bǔ)充的。

4.閑聊

上面寫的我意猶未盡,可能是自己知識(shí)的局限性暫時(shí)只能想到那些,上面說到了for...in,那么我們來簡(jiǎn)單的說一下for...of和它的區(qū)別。

他們都是遍歷用的,每次遍歷數(shù)組和對(duì)象都會(huì)想起它們,那么你會(huì)不會(huì)弄混呢。

那我們直接遍歷一次,看看有什么區(qū)別。

let arr = [8,{a: 1},6,6,8];
let a = {
    b:1,
    r: 8,
    h:{
        e:6
    }
}
console.log("for...of");
for(let i of arr){
    console.log(i); 
}
console.log("for...in");    
for(let i in a){
    console.log("key:" + i);  
}


是不是感覺挺好的,我們?cè)賮砜纯础?/p>

let arr = [8,{a: 1},6,6,8];
let a = {
    b:1,
    r: 8,
    h:{
        e:6
    }
}
console.log("for...in遍歷數(shù)組");
for(let i in arr){
    console.log(i); 
}
console.log("for...of遍歷對(duì)象");    
for(let i of a){
    console.log("key:" + i);  
}

for...of遍歷對(duì)象直接報(bào)錯(cuò)了,你有沒有注意到報(bào)錯(cuò)的信息。就是不可遍歷,因?yàn)椴皇莍terable。數(shù)組、字符串、Set、Map,內(nèi)置好了Iterator(迭代器),它們的原型中都有一個(gè)Symbol.iterator方法,而Object對(duì)象并沒有實(shí)現(xiàn)這個(gè)接口,使得它無法被for...of遍歷。

至于for...of遍歷對(duì)象就需要實(shí)現(xiàn)Iterator,這里我就不寫了,百度好多。

for...in遍歷數(shù)組遍歷出來的是索引。不過我們也可以得到數(shù)組的值。

for(let i in arr){
    console.log(arr[i]); //[8,{a: 1},6,6,8]
}

我覺得你看到這里應(yīng)該知道遍歷什么用哪個(gè)更合適了。

補(bǔ)充

__proto__的實(shí)現(xiàn)

Object.defineProperty(Object.prototype, __proto__, {
   get: function(){
       return Object.getPrototypeOf(this);
   },
   set: function(ob){
       Object.setPrototypeOf(this, ob);
       return ob;

})
 ```

下一篇文章我想說一下數(shù)組去重好像不是最全的數(shù)組去重方法,因?yàn)閮?nèi)容挺多,我就不一起寫了,喜歡的可以點(diǎn)一個(gè)贊,或者關(guān)注一下。鼓勵(lì)一下一名自學(xué)前端的大學(xué)生。

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

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

Failed to recv the data from server completely (SIZE:0/8, REASON:closed)