美文网首页
基本数据与引用数据的区别

基本数据与引用数据的区别

作者: 于美美 | 来源:发表于2022-10-17 19:13 被阅读0次

    基本数据: Undefined、Null、Boolean、Number、String、Symbol
    引用数据: Object、Array、Function、RegExp、Date

    注意: javascript不允许直接访问内存位置,因此就不能直接操作对象所在的内存空间

    一、基本数据与引用数据区别

    基本数据:

    • 大小是固定的,因此数据是保存在栈里的
    • 是按值访问的
    • 从一个变量到另一个变量复制原始值会创建该值的第二个副本

    引用数据:

    • 引用值是对象,存储在堆里,大小是不固定的
    • 从一个变量到另一个变量复制引用值只会复制指针,因此结果是两个变量都指向同一个对象
    • 保存引用值的数据是按引用访问的,它在栈只保存了指针,实际的内容是存在堆里,存在栈里的指针指向堆里的实际内容(当被访问时,是先访问指针,然后沿着指针的指向找到堆里的实际内容)

    当它们复制值时:
    基本数据:把基本数据通过变量赋值给另一个变量时,基本数据会被复制到新变量的位置
    引用数据:把引用数据通过变量赋值给另一个变量时,存储在变量中的值也会被复制到新变量所在的位置。区别就在于,这里复制的值实际上是一个指针,它指向存储在堆内存中的对象,操作完成后,两个变量实际上指向同一个对象,因此一个对象上面的变量会在另一个对象上反映出来,就会有深拷贝与浅拷贝

    基本数据.jpeg 引用数据.jpeg
    二、深拷贝与浅拷贝的区别

    深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。

    深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆数据开辟一个新的区域存放新对象,新旧对象不共享同一个内存,且修改对象不会影响另一个对象

    浅拷贝:如果对象的属性是基本类型,那拷贝的就是基本类型的值;如果是引用类型,那拷贝的就是指针,新旧对象共享同一块内存

    三、深拷贝与浅拷贝的一些实现

    浅拷贝

    • 展开运算符... ,实现浅拷贝
    let obj1 = {
      name: 'jack',
      age: 19,
      hobby: ['swimming', 'walking', 'go']
    }
    
    let obj2 = {...obj1}
    
    obj2.age=30
    obj2.hobby[0] = 'haha' 
    // obj1 ==> { age: 19, name: "jack", hobby:  ["haha", "walking", "go"] }
    

    以上:浅拷贝,第一层的数据如果是基本类型,是可以实现拷贝的,但是数据是引用类型,修改新对象的属性就会影响原对象的属性

    • Object.assign(),实现浅拷贝
    let obj2 = Object.assign({}, obj1);
    
    • Array.prototype.concat()
    let arr2 = arr1.concat([]);
    
    • Array.prototype.slice()
    let arr2 = arr1.slice();
    

    注意:当原数据(object)只有一层时,就是深拷贝; 当Array只有一层的时候,是深拷贝;所以当原数据进行浅拷贝,改变arr2的arr[1],而原数据arr1中的arr1[1]没有改变

    深拷贝

    • JSON.parse(JSON.stringify())
    let obj2 = JSON.parse(JSON.stringify(obj1))
    let arr2 = JSON.parse(JSON.stringify(arr1))
    

    Object、Array可以通过JSON.parse(JSON.stringify())实现深拷贝,但是Date跟Function却不能

    • jQuery.extend()方法
    //  需要引入jQuery库哦
    let obj2 = jQuery.extend(true, {}, obj1)
    
    • 手写递归实现深拷贝
    // 检测数据类型的功能函数
    const checkedType = (target) => Object.prototype.toString.call(target).replace(/\[object (\w+)\]/, "$1").toLowerCase();
    // 实现深拷贝(Object/Array)
    const clone = (target) => {
        let result;
        let type = checkedType(target);
        if(type === 'object') result = {};
        else if(type === 'array') result = [];
        else  return target;
        for (let key in target) {
            if(checkedType(target[key]) === 'object' || checkedType(target[key]) === 'array') {
                result[key] = clone(target[key]);
            } else {
                result[key] = target[key]; 
            }
        }
        return result;
    }
    

    调用一下手写递归实现深拷贝方法:

    const obj = {
        name: 'Chen',
        detail: {
            age: '18',
            height: '180',
            bodyWeight: '68'
        },
        hobby: ['see a film',  'write the code',  'play basketball', 'tourism']
    }
    
    const obj1 = clone(obj);
    console.log(obj1); // { name: 'Chen',detail: { age: '18', height: '180', bodyWeight: '68' },  hobby: [ 'see a film', 'write the code', 'play basketball', 'tourism' ]}
    console.log(obj1 === obj); // false
    
    判断数据类型
    • typeof:只能判断该变量是否为原始值,如果值为null或者对象,那么会返回'object'
    let s = 'string'
    let num = 10
    let b = true
    let u = undefined
    let nu = null 
    let o = new Object()
    
    console.log(typeof s) //  "string"
    console.log(typeof num) // "number"
    console.log(typeof b) // "boolean"
    console.log(typeof u) // "undefined"
    console.log(typeof nu) // "object"
    console.log(typeof o) // "object"
    
    • instanceof:instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上(原理:因为A instanceof B 可以判断A是不是B的实例,返回一个布尔值,由构造类型判断出数据类型)
    function Car(make, model, year) {
      this.make = make;
      this.model = model;
      this.year = year;
    }
    const auto = new Car('Honda', 'Accord', 1998);
    
    console.log(auto instanceof Car) // expected output: true
    console.log(auto instanceof Object) // expected output: true
    
    console.log([1,2,3] instanceof Array ); // true
    console.log(new Date() instanceof Date ); // true
    console.log(function f() {} instanceof Function ); // true
    
    • Object.prototype.toString.call
    console.log(Object.prototype.toString.call("jerry"));//[object String]
    console.log(Object.prototype.toString.call(12));//[object Number]
    console.log(Object.prototype.toString.call(true));//[object Boolean]
    console.log(Object.prototype.toString.call(undefined));//[object Undefined]
    console.log(Object.prototype.toString.call(null));//[object Null]
    console.log(Object.prototype.toString.call({name: "jerry"}));//[object Object]
    console.log(Object.prototype.toString.call(function(){}));//[object Function]
    console.log(Object.prototype.toString.call([]));//[object Array]
    console.log(Object.prototype.toString.call(new Date));//[object Date]
    console.log(Object.prototype.toString.call(/\d/));//[object RegExp]
    
    // 封装获取数据类型
    function getType(value) {
        let type = typeof value;
        if (type !== 'object') { // 如果是基本数据类型,直接返回
            return type;
        }
        // 如果是引用数据类型,再进一步判断,正则返回结果
        return Object.prototype.toString.call(value).replace(/^\[object (\S+)\]$/, '$1');
    }
     
    console.log(getType(123)) // 'number'
    console.log(getType('aaa')) // 'string'
    console.log(getType(() => {})) // 'function'
    console.log(getType([])) // 'Array'
    console.log(getType({})) // 'Object'
    console.log(getType(null)) // 'Null'
    

    参考文章:前端面试 第三篇 js之路 深拷贝与浅拷贝

    相关文章

      网友评论

          本文标题:基本数据与引用数据的区别

          本文链接:https://www.haomeiwen.com/subject/ntvjzrtx.html