• 一篇文章读懂javascript数据类型相关知识


    在前端开发中,很多小伙伴在使用javascript的时候只重视其功能性而忽视了其语言性,这不利于我们养成良好的编程习惯。这里给大家详细总结一下javascript的数据类型。

    熟悉java的同学知道,java里分为八大数据类型分别是boolean byte char short int long float double,而javascript的数据类型要多于java,可以按照内存使用的不同分为2大类。

    两种数据类型及内存分布

    第一类叫基本类型 有 null undefined boolean string number symbol 基本类型顾名思义就是由基本数据构成的,是直接存在内存的栈中的,基本类型的值是不可以改变的,当给一个基本类型重新赋值的时候,会在内存中开辟一个新的空间,旧值和新值是不同的指向。

    基本类型中除了null都是值类型,值类型在栈内存中的形态如下图,其中包含了变量的名称和变量的值。let a = 1,flag = true,name = "panda"

    null这个值比较特殊,按照大类划分属于基本类型,按照内存又属于引用类型,不过它的指针指向为空。

    栈内存区域
    a 1
    flag true
    name panda

    第二类叫引用类型 有 object array function ,引用类型其实都可以称为对象。引用类型的值是可以改变的,并可以添加属性和方法,和基本类型不同,引用类型实际上是通过存储在栈内存中的值指向到了堆内存中的,构成两者的关系叫做指向或者指针,下面画一个图表示引用类型在堆内存中的形态。function属于特殊引用类型,但不属于数据储存,所以没有下面会提到的深浅拷贝问题。

    let a = {};

    let b = a;

    新建一个对象a,在栈内存中的key是对象名a value是内存地址,同时,会在堆内存中开辟一个空间,key是内存地址,value是对象的值。

    当我们执行b=a的时候,会在栈中开辟个新空间,而不会在堆中开辟一个新空间,因此a和b的内存地址都等于a的内存地址。

     什么是深拷贝?什么是浅拷贝?

     从图上我们可以看出来,引用类型的赋值,其实就是栈区的指针的赋值。设想一下,这个时候我们把a赋值给b,b和a指向的就是同一个堆地址,这个时候无论改变a还是b都会改变另一个。这里强调一点,引用类型的比较其实是引用的比较,而不是大家理解的值的比较,用代码表示就是 

    let obj1 = {};
    let obj2 = {};
    obj1==obj2 // false

    回到刚才对象赋值会互相影响的问题,在我们日常开发中,会经常遇到需要copy对象的情况,比如data1为模板数据,想拷贝data1赋值给data2,我们改变data2的时候不想改变模板的数据,这里就引出了深拷贝和浅拷贝的概念。这里申明一点,深拷贝和浅拷贝都是为了解决对象赋值的问题的,有的同学理解为let data2 = data1 这样就是浅拷贝,连同引用地址一起改变了这样就是深拷贝,这种理解是错误的。

    从概念上来说 只改变数据第一层的指向的拷贝叫做浅拷贝,改变数据所有内容指向的拷贝叫做深拷贝。一半我们写代码的时候浅拷贝基本可以满足需求,但是遇到复杂的数据的时候是需要深拷贝实现的

    浅拷贝的方法:

    第一种:

      let a = {
        age: 1
      }
      let b = Object.assign({}, a)
      a.age = 2
      console.log("Object.assign方法:"+b.age) // 1
    第二种
      let c = {
        age:1,
      }
      let d = {...c}
      c.age = 2
      console.log("扩展运算符方法:"+d.age)

    深拷贝的方法:

    第一种: 通过二次转换实现,局限性:会忽略掉函数和undefined,循环引用的无效
    let a = {
      age: 1,
      jobs: {
        first: 'FE'
      }
    }
    let b = JSON.parse(JSON.stringify(a))
    a.jobs.first = "be"
    console.log("通过二次转换实现:",b)
    
    

    第二种:给大家提供一个深拷贝函数,原理是通过递归

          function deepClone(target) {
            // 定义一个变量
            let result;
            // 如果当前需要深拷贝的是一个对象的话
            if (typeof target === 'object'||typeof target== null) {
            // 如果是一个数组的话
                if (Array.isArray(target)) {
                    result = []; // 将result赋值为一个数组,并且执行遍历
                    for (let i in target) {
                        // 递归克隆数组中的每一项
                        result.push(deepClone(target[i]))
                    }
                // 判断如果当前的值是null的话;直接赋值为null
                } else if(target===null) {
                    result = null;
                // 判断如果当前的值是一个RegExp对象的话,直接赋值    
                } else if(target.constructor===RegExp){
                    result = target;
                }else {
                // 否则是普通对象,直接for in循环,递归赋值对象的所有值
                    result = {};
                    for (let i in target) {
                        result[i] = deepClone(target[i]);
                    }
                }
            // 如果不是对象的话,就是基本数据类型,那么直接赋值
            } else {
                result = target;
            }
            // 返回最终结果
            return result;
          }
          let c = {
            name:undefined,
            fun:function(){},
            val:1
          }
          c.age = c.name
          c.val2 = c.val
          let d = deepClone(c)
          console.log("递归复制:",d)
     

     如何判断数据类型

    了解了两种数据类型的不同之后,我们还要了解如何去判断一个数据类型,这里给大家列举了三个方法:

    第一种是typeof 返回字符串 用法如下: 

    需要注意的是 typeof 返回6种结果,对象和数组返回object ,函数返回function ,基本类型中null返回object(算是js的一个bug),NaN代表空数字也返回nubmer,

    用途:1 可以识别所有值类型(除了null之外的5种基本类型) 2 识别函数 3 判断是否是引用类型(判断不出来具体是哪一种引用类型)

      var a = [34,4,3,54],
            b = 34,
            c = 'adsfas',
            d = function(){console.log('我是函数')},
            e = true,
            f = null,
            g;
    
            console.log(typeof(a));//object
            console.log(typeof(b));//number
            console.log(typeof(c));//string
            console.log(typeof(d));//function
            console.log(typeof(e));//boolean
            console.log(typeof(f));//object
            console.log(typeof(g));//undefined

    第二种是 instanceof 返回布尔值:

    instanceof一般用来判断 a是不是b的实例,利用这一点可以精确判断出对象的数据类型,涉及原型和原型链的知识后面会单独写一篇文章为大家讲解

    用法:

    [] instanceof Array //true
    {} instanceof Object//true
    function(){}  instanceof Function//true

    100 instanceof Array //false
    "panda" instanceof object //false

    第三种是 Object.prototype.toString.call() 方法,用这个方法可以精确判断出所有数据类型(推荐)

    Object.prototype.toString.call(null); // "[object Null]"
    Object.prototype.toString.call(undefined); // "[object Undefined]"
    Object.prototype.toString.call(“abc”);// "[object String]"
    Object.prototype.toString.call(123);// "[object Number]"
    Object.prototype.toString.call(true);// "[object Boolean]"
    **函数类型**
    Function fn(){
      console.log(“test”);
    }
    Object.prototype.toString.call(fn); // "[object Function]"
    
    
    
    **日期类型**
    var date = new Date();
    Object.prototype.toString.call(date); // "[object Date]"
    
    
    
    **数组类型**
    var arr = [1,2,3];
    Object.prototype.toString.call(arr); // "[object Array]"
    
    
    
    **正则表达式**
    var reg = /[hbc]at/gi;
    Object.prototype.toString.call(reg); // "[object RegExp]"
     
  • 相关阅读:
    Android WifiDisplay分析一:相关Service的启动
    Android4.2以后,多屏幕的支持 学习(一)
    第十七篇 --ANDROID DisplayManager 服务解析一
    Android Wi-Fi Display(Miracast)介绍
    Ubuntu下 Astah professional 6.9 安装
    JAVA调用c/c++代码
    Application Fundamentals
    说说Android应用的persistent属性
    Tasks and Back stack 详解
    Activity的四种launchMode
  • 原文地址:https://www.cnblogs.com/panda-programmer/p/12990418.html
Copyright © 2020-2023  润新知