JS数据类型之间的区别

81 阅读5分钟

44、数据类型之间的区别

数据类型分为两种
    1.基本数据类型(简单数据类型)
    2.引用数据类型(复杂数据类型)
!1.存储
    变量的数据存储的地方是 内存中,内存分为两个 栈内存,堆内存
    ** 基本数据类型存储在 栈内存中,比如:string number undefined null boolean
    ** 复杂数据类型,将数据本体存放在堆内存中,比如对象或者数组或者函数,然后将指向该内存的地址,
            存放在数组名或者对象名或者函数名中,数组/对象/函数 名 存放在 栈内存中
    ```js
        var num = 100
        var str = 'abc'
        var obj = {
            a: 1,
            b: 2
        } 
        var arr = [1, 2, 3, 4]
    ```
面试官:数据类型之间有什么区别?
基本数据类型有哪些(string number undefined null boolean),然后他们存储的地方是栈内存中
引用数据类型有哪些(对象或者数组或者函数)。然后他们数据本体存放的地方是堆内存中。然后变量名在储的位置是栈内存中
**!!!基本数据类型内部存储的是值;引用数据类型内部存储的是地址**
!2.赋值
 * 基本数据类型:赋值之后,两个变量之间没有任何关系,相当于将我自己的某一个东西,复制一份给你,然后你的就是你的,我的就是我的
 *   例子:我有一张考试卷,然后我复制一份给你,然后你在卷子上书写答案,并不会影响到我自己原本的这张卷子
 * 复杂数据类型:赋值以后,因为变量内部存储的是指向堆内存的地址 所以在赋值的时候,其实是将这个地址给到了另外一个变量 那么相当于这两个变量存储的是同一个钥匙 所以操作其中一个变量的时候,会影响另外一个变量
 *   例子:我房间有一个开门的钥匙,我将我的钥匙复制一份,给到你,那么此时我们两个共同拥有了一个房间的钥匙
 *       此时如果我对房间的布局做了修改,那么你进入房间的时候你能看到布局的修改 
 *       此时如果你将房间的所有东西全都偷走,那么我进入房间的时候能看到房间所有东西都被偷走了
 ```js
     var num1 = 100
     var num2 = num1
     var num2 = 666
     console.log(num1) //100
     console.log(num2) //666
     var obj1 = {
         name: 'QF001',
         age: 18
     }
     var obj2 = obj1;//这一步相当于将变量obj1内部存储的"钥匙", 给到了变量obj2,那么此时 obj2和 obj1相当于操作的是一个内存空间
     console.log(obj2) //{name: 'QF001', age: 18}
     obj2.name = 'QF666'
     console.log(obj2) //{name: 'QF006', age: 18}
     console.log(obj1) //{name: 'QF006', age: 18}
     /***
     * 首先创建了一个对象obj1 数据本体为:{name: 'QF0o1', age: 18} 然后变量名存储的是指向堆内存的地址,我们假设为XF0O1
     * 
     * 然后创建了一个对象obj2内部存储的是和 obj1一样的地址
     * 
     * 此时相当于obj2和 obj1共同保管一个内存空间
     * 
     * 换句话说:操作obj2会影响obj1 操作obj1也会影响obj2
     * */
 ```
!3.比较
 *          基本数据类型:就是值的比较
 *          引用数据类型:比较的时候 比较的是 存储地址
 ```js
     var obj1 = {name: 'QF001', age: 18}
     var obj2 = {name: 'QF001', age: 18}
     obj2.name = 'QF666'
     console.log(obj1.name) // QF001
     console.log(obj1 === obj2) //false
     /**
     *引用数据类型在对比的时候,对比的是地址,而这两个对象的地址完全不同,所以返回的结果是false
     * */  
     var num1 = 100
     var num2 = 200
     console.log(num1 === num2) //false
     var arr1 = [1, 2, 3]
     var arr2 = arr1
     console.log(arr1 === arr2) //true
     //引用数据类型在对比的时候,对比的是地址 因为他们两个的地址完全相同,所以返回的结果是true
 ```
!4.传参
 *          基本数据类型:将值拷贝一份传递给形参,在函数内修改不会影响外界
 *          引用数据类型:将存储地址赋值给形参,在函数内修改会影响外界
 ```js
     function fn(num) {num = 'QF001'}
     var str = 'abc'
     fn(str) 
     console.log(str) //abc
     function fn1(o) {o.name = 'qwer'}
     var obj = {name: 'ABC'}
     fn1(obj)
     console.log(obj.name) //qwer
 ```
一道面试题:
    var obj = {name: 'Jack'}
    function fn() {
      obj.name = 'Rose'
      obj = {}
      obj.name = 'Jerry'
      console.log(obj.name) //Jerry
    }
    fn()
    console.log(obj.name) //Jerry
    //解析:
    /**
     * *  代码从上往下开始执行
     * *      创建一个变量 叫做 obj, 数据本体 {name: Jack}   假设内部存储的地址为 XF001
     * *      定义一个 fn 函数, 但是没调用, 所以直接向下走
     * *      调用函数, 开始执行函数内部代码, 函数的代码是
     *        obj.name = 'Rose'
     *        obj = {}
     *        obj.name = 'Jerry' 
     *        执行顺序还是从上往下
     * * 
     * *          开始执行函数内代码
     * *              obj.name = 'Rose'
     * *                 会先在当前作用域内查找有没有定义 obj 这个对象, 所以会向父级作用域查找
     * *                     在父级作用域, 找到了 全局变量 obj
     * *                     所以obj.name = 'Rose'相当于 修改了 全局变量 obj 的 name 属性
     * *              obj = {}
     * *                     会先在当前作用域内查找有没有定义 obj 这个对象, 所以会向父级作用域查找
     * *                     在父级作用域, 找到了全局变量 obj
     * *                     所以 obj = {} 相当于 修改 全局变量 obj 内部存储的地址, 此时这个变量为一个空对象了
     * *                     然后内部存储的地址 更改了 XF002, 与原本的地址没有任何联系了
     * *             obj.name = 'Jerry'
     * *                   会先在当前作用域内查找有没有定义 obj 这个对象, 因为没找到, 所以会向父级作用域查找
     * *                   在父级作用域, 找到了全局变量 obj
     * *                   然后给这个对象内部 添加一个 name 属性, 值 Jerry
     * *            console.log(obj.name) 
     * *                   根据分析我们此时可以得知, 我现在打印的对象应该是 全局对象 obj, 此时他的值已经被修改了
     * *                   所以此时打印的值 应该是 Jerry
     * *                  此时函数执行完毕, 代码继续向下执行
     * *      console.log(obj.name) 此时打印的是 当前作用域的变量 obj   因为现在 在全局作用域
     * *          所以会打印全局作用域的变量 obj,     因为在打印之前函数 fn执行时 已经修改过 obj 对象的内容
     * *          所以 此时 打印的时候 obj.name   应该是 Jerry
     * */