一篇就夠-JS數(shù)據(jù)類型

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

根據(jù)變量類型傳遞方式,可以分為基本數(shù)據(jù)類型和引用數(shù)據(jù)類型

  • 基本數(shù)據(jù)類型:Number、Boolean、String、Undefined、Null、Symbol(es6)
    • Null表示空對象指針
    • Undefined表示未定義
  • 引用類型:Object是所有引用類型的父對象
    • Object、Function、Arguments、Date、Math、Error、RegExp、自定義對象等

傳參方式

  • 基本數(shù)據(jù)類型和引用類型都是按值傳遞
  • 按值傳遞,傳遞的是變量里的內(nèi)容,不管盒子里面存的是基本類型值還是引用類型的地址
//不影響
var obj = {
    value: 1
};
function foo(o) {
    o = 2;
    console.log(o); //2
}
foo(obj);
console.log(obj.value) // 1
//影響
var obj = {
    value: 1
};
function foo(o) {
    o.value = 2;
    console.log(o.value); //2
}
foo(obj);
console.log(obj.value) // 2

存儲空間

基本數(shù)據(jù)類型存儲在內(nèi)存棧中,引用類型的數(shù)據(jù)存儲在堆中(引用存儲在內(nèi)存棧)


image

類型檢測

typeof

  1. 不要用typeof做類型檢測
  2. typeof null會錯(cuò)誤的返回Object
    • 在 JavaScript 最初的實(shí)現(xiàn)中,JavaScript 中的值是由一個(gè)表示類型的標(biāo)簽和實(shí)際數(shù)據(jù)值表示的。對象的類型標(biāo)簽是 0。由于 null 代表的是空指針(大多數(shù)平臺下值為 0x00),因此,null 的類型標(biāo)簽是 0,typeof null 也因此返回 "object"
  3. typeof Function會返回function
  4. typeof 無法區(qū)別基本數(shù)據(jù)類型和引用類型
// 下面的例子令人迷惑,非常危險(xiǎn),沒有用處。避免使用它們。
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';

類型檢測的通用方法

使用Object.prototype.toString()可以獲取對象的[[Class]]內(nèi)部屬性。[[Class]]內(nèi)部屬性根據(jù)標(biāo)準(zhǔn),只可能是下面字符串中的一個(gè):
Arguments, Array, Boolean, Date, Error, Function, JSON, Math, Number, Object, RegExp, String.

function isType(obj,type){
    //[object xxx]
    let classProperty = Object.prototype.toString.call(obj).slice(8,-1)
    return classProperty === type
}
//true
is(new String("a"),"String")
//true
is("a","String")

instanceof

object instanceof constructor用來檢測一個(gè)對象是否為某個(gè)構(gòu)造函數(shù)的實(shí)例

function A() {
}
function B() {
}
B.prototype = new A()
let b = new B()
b instanceof B // true
b instanceof A // true

instanceof原理:

//判斷當(dāng)前構(gòu)造函數(shù)的prototype是否在原型鏈上
function new_instance_of(leftVaule, rightVaule) { 
    let rightProto = rightVaule.prototype; // 取右表達(dá)式的 prototype 值
    leftVaule = leftVaule.__proto__; // 取左表達(dá)式的__proto__值
    while (true) {
        if (leftVaule === null) {
            return false;   
        }
        if (leftVaule === rightProto) {
            return true;    
        } 
        leftVaule = leftVaule.__proto__ 
    }
}

加深原型鏈理解:


image
  • 可以知道prototype是構(gòu)造函數(shù)獨(dú)有屬性,proto是任意對象都有的(不管當(dāng)前對象是作為構(gòu)造函數(shù)還是原型,)并且指向其構(gòu)造函數(shù)的prototype,constructor的是原型獨(dú)有的屬性
  • Function對象是任意構(gòu)造函數(shù)的構(gòu)造函數(shù)(包括function Object),所以任意構(gòu)造函數(shù)的proto指向Function.prototype
  • 任意對象最終繼承自O(shè)bject.prototype(最終proto指向Object.prototype),Object.prototype.proto按規(guī)定是null
  • Function的prototype和proto都指向Function.prototype
function Foo() {
}

//因?yàn)镺bject作為函數(shù)則Object.__proto__等于Function.prototype,而Function.prototype是對象,所以Function.prototype.__proto__為Object.prototype
Object instanceof Object // true
Function instanceof Function // true
Function instanceof Object // true
Foo instanceof Foo // false
Foo instanceof Object // true
Foo instanceof Function // true

賦值、淺拷貝和深拷貝

image

賦值和淺拷貝的區(qū)別

  • 如果將一個(gè)對象賦值給新變量,賦的是對象在棧中的地址,不是堆中的數(shù)據(jù)。也就是新的變量和賦值的對象指向同一個(gè)存儲空間。
  • 淺拷貝是按位拷貝,會創(chuàng)建一個(gè)新的對象,對原始對象的屬性進(jìn)行拷貝,如果屬性是基本類型,則拷貝的是基本類型的值,如果屬性是引用類型,則拷貝的是引用類型的內(nèi)存地址。
//對象賦值
var obj = {
    name:'johe',
    age:'18',
    arr:[1,2]
}
var obj2 = obj
obj2.name = 'johe-test'
//受影響
obj.name
//淺拷貝
var obj = {
    name:'johe',
    age:'18',
    arr:[1,2]
}

function shallowCopy(obj){
    var cloneObj = {}
    for(let property in obj){
        // for in 會訪問原型鏈上的屬性,所以需要加判斷
        if(obj.hasOwnProperty(property)){
            cloneObj[property] = obj[property]
        }
    }
    return cloneObj
}

var obj2 = shallowCopy(obj)
obj2.name="johe-test"
//不受影響,輸出johe
obj.name
obj2.arr[1] = 3
//受影響,輸出[1,3]
obj.arr

淺拷貝實(shí)現(xiàn)方式

  • Object.assign:把任意多個(gè)源對象的可枚舉屬性拷貝給目標(biāo)對象,然后返回目標(biāo)對象。當(dāng)被拷貝對象只有一層(一層全是基本數(shù)據(jù)類型)時(shí),是深拷貝
var obj = {
    arr:[1,2]
}
var cloneObj = Object.assign({},obj)
cloneObj.arr = [1,3]
//受影響,輸出[1,3]
obj.arr
  • Array.prototype.concat()
let arr = [1,2,{name:'johe'}]
let arr2 = arr.concat[]
arr2[2].name = "johe-test"
//受影響輸出johe-test
arr[2].name
  • Array.prototype.slice()

淺拷貝和深拷貝的區(qū)別

image

淺拷貝和深拷貝都會返回一個(gè)新對象,淺拷貝在拷貝對象屬性時(shí),如果是基本數(shù)據(jù)類型,則拷貝值,如果是引用類型,則拷貝引用(指向同一地址)。
深拷貝在拷貝對象屬性時(shí),如果是基本數(shù)據(jù)類型,則拷貝值,如果是引用類型,則生成新對象遞歸拷貝。

深拷貝實(shí)現(xiàn)

  • JSON.parse(JSON.stringify()):最常用的深拷貝方法,但不能處理函數(shù)和正則
  • 手寫遞歸方法:
function isType(type,obj){
    return Object.prototype.toString.call(obj).slice(8,-1) === type
}

function deepClone(target){
    let result
    if(isType('Object',target)){
        result = {}
    }else if(isType('Array',target)){
        result = []
    }else{
        return target
    }
    for(let i in target){
        let value = target[i]
        result[i] = deepClone(value)
    }
    return result
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容