数据类型的区别(及数组方法)

104 阅读12分钟

数据类型的区别

  • 基本数据类型

  数字, 字符串, 布尔值, undefined, null

  • 引用数据类型

   函数, 对象, 数组

  1. 存储的区别
  • 基本数据类型存储在 栈内存中, 比如: string; number; undefined; null; boolean

  • 复杂数据类型(引用数据类型)

    • 将数据本体存放在 对内存中, 比如对象或者数组, 然后将指向该堆内存的地址, 存放在数组名或者对象名中
    • 数组名或者对象名放在栈内存中
  • 两种数据类型的区别

    • 基础数据类型直接存储在 栈内存中, 变量中存储的是数据
    • 复杂数据类型会将数据本体存放在堆内存中, 变量名存储在堆内存中,变量名内部存储着指向堆内存的地址
    var arr1 = [1,2,3]   //假设地址为QF 001
    var arr1 = [1,2,3]   //假设地址为QF 002
    var arr3 = arr1   //QF001
    console.log('arr1: ', arr1) // [1, 2, 3]
    console.log('arr2: ', arr2) // [1, 2, 3]
    console.log('arr3: ', arr3) // [1, 2, 3]

    console.log('===============================')

    arr3[0] = '我是一个新的数据'
    console.log('arr1: ', arr1) // ['我是一个新的数据', 2, 3]
    console.log('arr2: ', arr2) // [1, 2, 3]
    console.log('arr3: ', arr3) // ['我是一个新的数据', 2, 3]
  1. 赋值的区别
  • 基本数据类型: 将变量中的数据赋值给另一个变量
    • 赋值以后, 两个变量没有关系了,相当于将我自己的某一个东西, 复制一份给到你, 然后你的是你的, 我的是我的
  • 复杂数据类型:将变量中的地址赋值给另一个变量
    • 赋值以后,两个变量操作一个存储空间, 相当于我将我房间的钥匙复制一份给到你,你可以自由进出该房间或者对这个房间的布局进行一些调整, 我可以自由进出该房间并且可以对房间的布局做调整
  1. 比较的区别

    • 基本数据类型是 '值' 的比较
    • 引用数据类型是 '地址' 的比较
  2. 传参的区别

  • 基本数据类型: 将变量内部的数据复制一份, 传递给对应的形参,所以函数内对这个形参的修改不会影响外界
  • 引用数据类型: 将变量内部的地址复制一份, 传给对应的形参,所以此时函数内形参和变量的内部是同一个地址
  • 所以在函数内部对这个形参的一些修改, 会影响外界
    // 1. 基本数据类型
        var num = 100
        function fn(a) {
            console.log('fn 函数内部的形参 a, 被修改前: ', a)
            a = 'QF001'
            console.log('fn 函数内部的形参 a, 被修改后: ', a)
        }
        fn(num)
        console.log(num)    // 100
     // 2. 引用数据类型
        var arr = [1, 2, 3]

        // function fn(a) {
        //     /**
        //      *  因为 fn 函数在传递实参的时候是传递的全局变量 arr, 根据规则, 会将arr内部的地址, 复制一份给到 形参a
        //      *x
        //      *  所以我们可以说 形参a 和 全局变量 arr, 内部的地址完全相同
        //      * 
        //      *  那么如果在函数内部对形参这个地址内的数据做了一些修改, 函数外的全局变量也会被影响
        //     */
        //     a[0] = 'QF001'
        // }

        function fn(a) {
            /**
             *  当前函数 fn 调用的时候传递的是一个数组 arr, 那么根据规则会将 arr 内部的地址 复制一份给到形参a
             * 
             *  根据规则的说明, 我们在函数中对这个形参的一些修改会影响外界
             * 
             *  但前提是形参和外边变量的内部都是存着同一个地址
             * 
             *  我们的处理方式是将 形参a内部的一个地址重新更改为一个字符串
             *  我们没有修改这个地址内部的任何东西, 我们只是将形参a内部存储的地址更改为了一个字符串,
             * 
             *  所以这一步操作相当于 切断了当前形参和全局变量之间的唯一联系
            */
            console.log('修改前的形参: ', a)
            a = 'QF001'
        }

        fn(arr)
        console.log('arr: ', arr)

课堂案例

     var arr = [1, 2, 3]
        function fn(arr) {
            arr[0] = '新的字符串'
            arr = [4, 5, 6]
            arr[0] = '最新的字符串'
            console.log(arr)
        }
        fn(arr)

        console.log(arr)    // ['新的字符串', 2, 3]
        
          /*
            var arr = [1, 2, 3]             // 1. 假设内部的地址为 QF001

            function fn(arr) {              // 3. 因为调用传递的实参, 所以可以确定当前形参 arr 和 全局变量 arr, 是同一个地址
                arr[0] = '新的字符串'       // 4. 因为函数的形参就是 arr, 所以此时不会访问到全局 arr, 我们这里是通过形参arr给 QF001 这个地址内部的数据 [0] 的位置重新更改了一个值, 注意: 此时会影响全局变量的值
                arr = [4, 5, 6]             // 5. 将 形参 arr 重新赋值为一个 新的数组, 那么此时就是将原本的地址 QF001 更改为了 QF002,   注意: 此时切断了 形参arr 和 全局变量arr 的联系
                arr[0] = '最新的字符串'     // 6. 通过 形参arr 对 QF002 内的数据 [0] 的值做一个修改, 注意: 此时的修改不会影响全局变量 arr
            }

            fn(arr)                         // 2. 调用 fn 函数, 并将 全局变量 arr 内部的地址(QF001) 复制一份传递给 形参 arr

            console.log(arr)    // ['新的字符串', 2, 3]
        */

面试题

 // 题目1
        // var obj = {
        //     name: '张三'
        // }
        // function fn() {
        //     obj.name = '李四'   // 此时开始在当前作用域内寻找变量 obj, 但是没有找到, 不过在上一层的全局作用域有一个变量叫做 obj, 正好是一个对象 也有 name 属性, 全局变量 obj 的name属性被修改为 '李四'
        //     obj = {}            // 将全局变量 obj 重新修改为 一个空对象
        //     obj.name = '王五'   // 将全局变量 obj 内部的 新对象中 添加一个 name 属性, 值为 '王五'
        // }
        // fn()
        // console.log(obj.name)   // 王五

    // 题目2
        // var obj = {
        //     name: '张三'
        // }
        // function fn() {
        //     obj.name = '李四'
        //     var obj = {}
        //     obj.name = '王五'
        //     /*
        //         函数内部原本的代码:
        //                 obj.name = '李四'
        //                 var obj = {}
        //                 obj.name = '王五'
        //         变量提升后:
        //                 var obj
        //                 obj.name = '李四'
        //                 obj = {}
        //                 obj.name = '王五'
        //     */
        // }
        // fn()
        // console.log(obj.name)   // 当前代码根本运行不到这里, 因为函数内部会报错
     // 题目3
        var obj = {
            name: '张三'
        }

        function fn(obj) {  // 因为传递的实参obj是引用数据类型的, 所以是将地址复制一份传递给形参obj, 所以此时形参obj和全局变量obj指向同一个对象(地址)
            
            obj.name = '李四'   // 在当前行执行的时候还是会发生变量提升, 但是此时因为当前函数有一个形参, 所以在定义并赋值变量前我们使用的是 形参 obj, 所以此时我们是通过 形参 obj 修改了一个地址内的数据, 又因为 全局变量 obj 和 形参obj 是同一个 地址, 所以此时会影响全局变量 obj
            
            var obj = {}        // 在当前函数内 声明并赋值了一个 变量, 变量名 obj, 变量的值 空对象
            obj.name = '王五'   // 将上述定义的局部变量内部新增一个属性 name, 对应的值为 '王五'
        } 

        fn(obj)

        console.log(obj.name)   // 李四

数组的常用方法

  1. push

    • 语法: 数组.push(参数)
    • 作用: 向数组的末尾新增一条数据
    • 返回值: 新增数据后,数据的最新长度 当前方法一般没人用 返回值
     // 1. push
        var arr = [1, 2, 3]
        console.log('原数据: ', arr)
        arr.push('一个新的数据')
        // var res = arr.push('一个新的数据')
        console.log('push 之后的数组: ', arr, res)
  1. pop
    • 语法: 数组.pop()
    • 作用: 删除数组末尾最后一个元素
    • 返回值: 被删除的数据 当前方法一般没人用
    // 2. pop
        var arr = [1, 2, 3, '我会被删除']
        console.log('原数组arr: ', arr)
        // arr.pop()
        var res = arr.pop()
        console.log('新数组arr: ', arr, res)
  1. unshift
    • 语法: 数组.unshift(参数)
    • 作用: 向数组的开头新增一条数据
    • 返回值: 新增数据后, 数组的最新长度 当前方法一般没人用
    // 3. unshift
        var arr = [1, 2, 3]
        console.log('原数组arr: ', arr)
        // arr.unshift('我是新增的数据')
        var res = arr.unshift('我是新增的数据')
        console.log('新数组arr: ', arr, res)
  1. shift
    • 语法: 数组.shift()
    • 作用: 删除数组开头的第一个元素
    • 返回值: 被删除的数据 当前方法一般没人用
    // 4. shift
        var arr = ['我是要被删除的数据', 1, 2, 3]
        console.log('原数组arr: ', arr)
        // arr.shift()
        var res = arr.shift()
        console.log('新数组arr: ', arr, res)
  1. reverse
    • 语法: 数组.reverse
    • 作用: 反转数组
    • 返回值: 反转后的数组
    // 5. reverse
       var arr = [1, 2, 3, 4, 5]
       console.log('原数组: ', arr)

       var res = arr.reverse()

       console.log('返回值: ', res)
       console.log('新数组: ', arr)
  1. sort
    • 语法1: 数组.sort()
    • 作用: 将数组中的所有的元素成员, 转换成字符串, 然后一位一位的对比
    • 语法2: 数组.sort(function (a, b) {return a - b})
    • 作用: 将我们数组内的数据按照数字的从小到大排序
    • 语法3: 数组.sort(function (a, b) { return b - a})
    • 作用: 将我们数组内的数据按照数字从大到小排列
    • 返回值: 排序后的数组
      // 6. sort  语法1: 数组.sort()
        var arr = [1, 2, 3, 10, 20, 30, 41, 100, 1000, 50000, 6, 11, 12]
        console.log('原数组: ', arr)
        var res = arr.sort()
        console.log('返回值: ', res)
        console.log('新数组: ', arr)


        // 6. sort  语法2: 数组.sort(function (a, b) { return a - b })
        var arr = [1, 2, 3, 10, 20, 30, 41, 100, 1000, 50000, 6, 11, 12]
        console.log('原数组: ', arr)

        var res = arr.sort(function (a, b) { return a - b })
        console.log('返回值: ', res)
        console.log('新数组: ', arr)

        // 6. sort  语法3: 数组.sort(function (a, b) { return b - a })
        var arr = [1, 2, 3, 10, 20, 30, 41, 100, 1000, 50000, 6, 11, 12]
        console.log('原数组: ', arr)
        var res = arr.sort(function (a, b) { return b - a })
        console.log('返回值: ', res)
        console.log('新数组: ', arr)
  1. splice

    • 语法1:数组.splice(开始位置/开始下标,多少个)
    • 作用: 类似于 剪切 的功能
    • 语法2: 数组.splice(开始位置/开始下标,多少个,新增的数据1, 新增的数据2, 新增的数据3.....)
    • 作用: 首先会按照两个参数指明的位置去剪切出来一个数据,然后将第二个数据以后的(第三个开始) 所有的数据,放在刚才剪切的位置
    • 返回值: 剪切到的数据
     // 7. splice    语法1: 数组.splice(开始位置/开始下标, 多少个)
        var arr = [1, 2, 3, 4, 5, 6, 7]
        //         0  1  2  3  4  5  6
        
        console.log('原数组: ', arr)
        // var res = arr.splice(2, 3)
        // console.log('返回值: ', res)
        // console.log('新数组: ', arr)
        
        // 7. splice    语法1: 数组.splice(开始位置/开始下标, 多少个)

        var res = arr.splice(1, 3, '新增的数据1', '新增的数据2', '新增的数据3', '新增的数据4')
        console.log('返回值: ', res)
        console.log('新数组: ', arr)

数组的其他方法(不影响数组)

  1. slice
    • 语法: 数组.slice(开始下标,结束下标)
    • 参数的特点
      • 包前不包后
      • 两个参数都可以省略不写
      • 参数可以支持 负数, 相当于 数组.length + 负数
    • 作用: 复制指定范围的内容
    • 返回值: 复制到的内容
       // 1. slice
        var arr = [1, 2, 3, 4, 5, 6, 7]
                // 0  1  2  3  4  5  6

        
        // 1.3 参数可以支持 负数
        var res = arr.slice(3, -1)  // (3, -1)  =>  (3, arr.length + (-1))  =>  (3, arr.length - 1))    =>    (3, 7 - 1))   => (3, 6))
        console.log(res)    //  [4, 5, 6]
     
        // 1.2 省略结束下标, 那么会从开始下标复制到数组的末尾
        var res = arr.slice(2)
        console.log('返回值: ', res)    // [3, 4, 5, 6, 7]

        // 1.2 开始与结束都省略, 相当于复制整个数组
        var res = arr.slice()
        console.log('返回值: ', res)    // [1, 2, 3, 4, 5, 6, 7]
        
        // 1.1 基本演示
        console.log('原数组: ', arr)
        var res = arr.slice(2, 5)
        console.log('返回值: ', res)    // [3, 4, 5]
        console.log('新数组: ', arr)

  1. concat
    • 语法: 数组.concat(数据1, 数据2, 数据3, 数据4........)
    • 作用: 将传入的数据, 合并到指定的数组中, 然后返回出来,
    // 2. concat
        var arr = [1, 2, 3]
        var res = arr.concat(4, 5, 6, [7, 8, 9], true, false, undefined, {name: 'QF001'})
        console.log('返回值: ', res)
        console.log('方法调用后的 arr: ', arr)
  1. join
    • 语法: 数据.join('连接符') 连接符如果不传递默认按照 , 连接
    • 作用: 根据传入的连接符 将数组内的所有的元素, 拼接成一个 完整的字符串
    • 返回值:拼接好的字符串
     // 3. join

        var arr = [1, 2, 3, 999]
        // var res = arr.join() // 如果不传参数, 默认按照 , 连接
        // var res = arr.join('$')
        // var res = arr.join(' ')
        // var res = arr.join('')
        var res = arr.join('|')
        console.log(res)
  1. indexOf

    • 语法:数组.indexOf(要查询的数据, 从哪里开始查询(下标)) 第二个参数不写默认为 0
    • 作用: 按照 从左到右(按照下标的从大到小) 的顺序 检查数组中是否包含指定数据
    • 返回值:
      • 查询到: 返回从左到右数据第一次出现的下标
      • 没有查询到: 返回-1
  2. lastIndexOf

    • 语法: 数组.lastIndexOf(要查询的数据, 从哪里开始查询(下标)) 第二个参数默认不写默认为 数组最后一个下标
    • 作用: 按照 从右到左(按照下标从大到小) 的顺序 检查数组中是否包含指定数据
    • 返回值:
      • 查询到: 返回从右到左数据第一次出现的下标
      • 没有查询到 : 返回 -1
     var arr = [1, 2, 3, 4, 5,1,2,3,4,5]
        //         0  1  2  3  4  5  6  7  8

        // console.log(arr.indexOf(1))         // 不传递第二个参数, 默认从 下标[0] 开始    0
        // console.log(arr.indexOf(1, 0))      // 从 下标 [3] 开始 在数组中查询 数字 1     8
        // console.log(arr.indexOf(100, 3))    // 从 下标 [3] 开始 在数组中查询 数字 100   -1

        // console.log(arr.lastIndexOf(1))         // 不传递第二个参数, 默认从 最后一个元素的下标 开始    8
        // console.log(arr.lastIndexOf(1, 3))      // 从 下标 [3] 开始 在数组中查询 数字 1     0
        // console.log(arr.lastIndexOf(100, 3))    // 从 下标 [3] 开始 在数组中查询 数字 100   -1
        for(let i = 0; i < arr.length;i++){
            var arr1=[]
            // console.log(arr.indexOf(i,0))
            if(arr.indexOf(i,0) === -1){
                // arr1.push(arr[i])
                // console.log(arr[i])
            }
        }
        console.log(arr1)

遍历数组的方法

  1. forEach
    • 语法: 数组.forEach(function(item, index, origin) { 遍历数组后你想要做的事 } )
    • 参数
      • item: 数组: 数组中每一个元素
      • index: 每个元素对应的下标
      • origin: 原数组 (一般不用)
    • 作用: 根据数组的元素内容, 循环遍历数组, 拿到数组的每一项
    • 返回值: 没有返回值
    • 语义: 遍历数组
      // 1. forEach
        var res = arr.forEach(function (item, index, origin) {})
        console.log(res) //undefined

        arr.forEach(function (item) {})
        arr.forEach(function (item, index) {})
        arr.forEach(function (a, b, c) {})
        arr.forEach(function (item, index, origin) {
            console.log('123', item, index, origin)
        })

        for (var i = 0; i < arr.length; i++) {
            console.log(arr[i], i, arr)
        }
  1. map
    • 语法: 数组.map( function (item, index, origin) { 遍历数组后你想要做的事} )
    • 参数:
      • item: 数组中的每一个元素
      • index: 每一个元素对应的下标
      • origin: 原数组
    • 作用: 根据原数据映射出来一个新数组
    • 返回值: 是一个映射出来的新数组(需要在函数内部书写return)
    • 语义: 映射数组
    var arr = [100, 200, 300, 400, 500]
        //          0   1     2     3   4

        // 2. map

        // 基本演示
        // arr.map(function (item, index, origin) {
        //     console.log(item, index, origin)
        // })

        var res = arr.map(function (item) {
            return item * 2
        })
        console.log(res)