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

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

作者: 于美美 | 来源:发表于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之路 深拷贝与浅拷贝

相关文章

  • 深入理解JS的数据类型

    js数据类型主要分为基本数据类型和引用数据类型 基本数据类型和引用数据类型的区别:基本数据类型是对值得引用,引用数...

  • Java的数据类型

    一、Java数据类型分为基本数据类型与引用数据类型。 二、基本数据类型 三、基本数据和包装类的区别 四、基本数据类...

  • JavaScript数据类型区分和检测

    基本数据类型和引用数据类型的区别先看一道面试题 图示解析如下: 所以,基本数据类型和引用数据类型的本质区别:基本数...

  • 基本数据类型和引用数据类型的区别

    引用数据和基本数据的区别 区别 从概念方法来说:基本数据类型:变量名指向具体的数值 ,引用数据类型:变量名指向存数...

  • java集合笔记

    集合和数组的区别 区别1:数组即可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据存储...

  • js数据类型

    JS基本数据类型和引用数据类型(JS 基本数据类型和引用数据类型的区别及浅拷贝和深拷贝) 再讲 js 的基本数据类...

  • JS数据类型

    数据类型分类和区别 分类 javascript数据类型分为:值类型(基本数据类型)、引用数据类型; 区别 值类型 ...

  • 基本包装类型

    JS中的数据分为基本数据和引用类型数据两大类,最大的区别在于: 基本数据类型的值不可变,引用类型可变 这里改变的只...

  • Java基础概念

    本系列文章着重介绍java与C++的区别。 一、数据类型 java言语数据类型只有两种:基本数据类型、引用数据类型...

  • java

    数据类型分为:8大基础数据类型和3大引用数据类型。 基础数据类型和引用数据类型的区别: 1,基本数据类型变量声明之...

网友评论

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

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