笔记六、JavaScript——数组

233 阅读17分钟

六、数组

1.认识数组

  • 数组 是一种数据类型, 他也是属于 引用数据类型(复杂数据类型)
  • 根据字面意思来说, 存放数字的一个组合, 但这样说有点片面了
  • 更完善的说法: 数组是存放一些数据的集合
  • 换句话说: 我们把数据放在一个盒子中, 这个盒子就叫做数组, 注意! 数组内的数据是有顺序的

2.创建数组

  • 分两种方式

    • 字面量的方式

      • 语法: var arr = [1, 2, 3, 'q', 'w', 'e']
    • 内置构造函数的方式

      • 语法1: var arr = new Array() 创建一个空数组
      • 语法2: var arr = new Array(5) 创建一个有长度的数组
      • 语法3: var arr = new Array(1, 2, 3) 创建一个有内容的数组

3.数组的 length 属性

  • length 翻译过来就是 长度的意思
  • 代表 这个数组内, 有多少个成员
  • 语法: 数组名.length

4.数组的索引

  • 索引 也有人叫做 下标
  • 就是指一个数据, 在这个数组内排列在第几个 位置上
  • 注意: 在 JS 中, 索引(下标) 是从 0 开始计算的
  • 如果想要获取到数组指定位置的值, 可以通过下标来获取
  • 语法: 数组名[下标] -> 能够获取到这个数组中对应下标的成员具体的值

5. 遍历数组

  • 想办法 拿到 数组的每一个成员
  • 想拿到数组的所有成员, 需要先想办法拿到数组的所有下标
  • 规律: 所有数组的下标都是从0开始的, 然后到 数组.length - 1 结束
var arr = ['b', 'a', 'c', 1, 2, 3]
// 需求, 就是根据 arr 这个数组, 拿到他的所有下标
for (var i = 0; i < arr.length; i++) {
// console.log(i)  // 0 1 2 3 4 5

// 需求: 拿到数组所有的值, 输出在控制台
 console.log(arr[i])
}
复制代码

6. 冒泡排序

  • 属于数组排序的算法之一

    • 其实就是通过一种算法, 将 一个乱序的数组, 调整为指定顺序的数组(从大到小/从小到大)
  • 什么是算法?

    • 解决某一个问题最简单的方式 / 最高效的方式
//准备一个乱序数组
var arr = [9, 3, 6, 2, 4, 1, 8, 5, 7]
console.log('原始数组: ', arr)

// 冒泡排序的核心: 对比数组前一项和后一项, 如果前一项的值较大, 那么就往后挪 (这个排序之后是按照从小到大的顺序)
for (var i = 0; i < arr.length; i++) {
    if (arr[i] > arr[i + 1]) {
        var temp = arr[i]
        arr[i] = arr[i + 1]
        arr[i + 1] = temp
    }
 }
 console.log('1 轮冒泡排序后的数组: ', arr)
复制代码
//基础版
var arr = [9, 3, 6, 2, 4, 1, 8, 5, 7] 
for (var k = 0; k < arr.length; k++) {
    //console.log("这是第", k + 1, '循环')
    for (var i = 0; i < arr.length; i++) {
        //console.log(arr[i], arr[i + 1])
        if (arr[i] > arr[i + 1]) {
            var temp = arr[i]
            arr[i] = arr[i + 1]
            arr[i + 1] = temp
        }
    }
}
console.log('基础版冒泡排序后的数组: ', arr)


//优化版
var arr = [9, 3, 6, 2, 4, 1, 8, 5, 7] 
for (var k = 0; k < arr.length - 1; k++) {
    //console.log("这是第", k + 1, '循环')
    for (var i = 0; i < arr.length - 1 - k; i++) {
        //console.log(arr[i], arr[i + 1])
        if (arr[i] > arr[i + 1]) {
            var temp = arr[i]
            arr[i] = arr[i + 1]
            arr[i + 1] = temp
        }
    }
}
console.log('优化版冒泡排序后的数组: ', arr)


//另一个版本
var arr = [9, 3, 6, 2, 4, 1, 8, 5, 7] 
for (var k = arr.length; k >= 0; k--) {
    for (var i = 0; i <=k; i++) {
        if (arr[i] > arr[i + 1]) {
            var temp = arr[i]
            arr[i] = arr[i + 1]
            arr[i + 1] = temp
        }
    }
}
console.log('另一个版本冒泡排序后的数组: ', arr)
复制代码

7.选择排序

var arr = [9, 8, 7, 6, 5, 4, 3, 2, 1]
//         0  1  2  3  4  5  6  7  8

//          第几次循环      假设谁是最小值      和谁交换    内层循环从几开始
//k === 0       1               0                 0              1
//k === 1       2               1                 1              2
//k === 2       3               2                 2              3
for (var k = 0; k < arr.length; k++) {
    var minIndex = k
    for (var i = k + 1; i < arr.length; i++) {
        if (arr[minIndex] > arr[i]) {
            minIndex = i
        }
    }    
    var temp = arr[k]
    arr[k] = arr[minIndex]
    arr[minIndex] = temp
}
console.log(arr)
复制代码

8.数据类型之间的区别

  • 数据类型分为两种

    1. 基本数据类型(简单数据类型)
    2. 引用数据类型(复杂数据类型)
  1. 存储
  • 变量的数据存储的地方是 内存中, 内存分为两个

    • 栈内存
    • 堆内存
  • 基本数据类型存储在 栈内存中, 比如: string number undefined null boolean

  • 复杂数据类型, 将数据本体存放在堆内存中, 比如对象或者数组或者函数,然后将指向该内存的地址, 存放在数组名或者对象名或者函数名中

  • 数组/对象/函数 名 存放在 栈内存中

  • 面试官: 数据类型之间有什么区别?

    • 基本数据类型有哪些, 然后他们存储的地方是 栈内存中
    • 引用数据类型有哪些, 然后他们数据本体存放的地方是 堆内存中, 然后变量名存储的位置是 栈内存中
    • 基本数据类型内部存储的是值; 引用数据类型内部存储的是地址

01.png2. 赋值

  • 基本数据类型: 赋值以后, 两个变量之间没有任何关系, 相当于将我自己的某一个东西, 复制一份给你, 然后你的就是你的, 我的就是我的

    • 例子: 我有一张考试卷, 然后我复制一份给你, 然后你在卷子上书写答案, 并不会影响到我自己原本的这张卷子
  • 复杂数据类型: 因为变量内部存储的是指向堆内存的地址, 所以在赋值的时候, 其实是将 这个地址给到了另外一个变量

    • 那么相当于这两个变量存储的是 同一个 钥匙, 所以操作其中一个变量的时候, 会影响另外一个变量
    • 例子: 我房间有一个开门的钥匙, 我将我的钥匙复制一份, 给到你, 那么此时我们两个共同拥有了一个房间的钥匙
    • 此时如果我对房间的布局做了修改, 那么你进入房间的时候你能看到布局的修改
    • 此时如果你将房间的所有东西全都偷走, 那么我进入房间的时候 能看到房间所有东西都被偷走了
var obj1 = {
    name: 'QF001',
    age: 18
}

// 这一步相当于将 变量 obj1 内部存储的 "钥匙", 给到了 变量 obj2, 那么此时 obj2 和 obj1 相当于操作的是一个内存空间
var obj2 = obj1

// console.log(obj2)   // {name: 'QF001', age: 18}

obj2.name = 'QF666'
console.log(obj2)   // {name: 'QF666', age: 18}
console.log(obj1)   // {name: 'QF666', age: 18}

复制代码
var obj1 = {
    name: 'QF001',
    age: 18
}
var obj2 = {
    name: 'QF001',
    age: 18
}

obj2.name = 'QF666'

console.log(obj1.name)   // QF001
/**
 *  1. 创建一个对象 obj1    内部存储的地址假设为 XF001
 *  2. 创建一个对象 obj2    内部存储的地址假设为 XF002
 * 
 *  注意此时两个对象除了长得一模一样之外  毫无关系
 * 
 *  也就是说  操作 其中一个对象, 并不会影响另外一个
*/
复制代码
  1. 比较
  • 基本数据类型: 就是 值 的比较
  • 引用数据类型: 比较的时候 比较的是 存储地址
var obj1 = {
    name: 'QF001',
    age: 18
}
var obj2 = {
    name: 'QF001',
    age: 18
}

console.log(obj1 === obj2)  // false
/**
 *  引用数据类型在对比的时候, 对比的是 地址     
 *  而这两个对象的地址完全不同, 所以返回的结果就是 false
*/

// var num1 = 100
// var num2 = '100'
// console.log(num1 === num2)  //  false

// var arr1 = [1, 2, 3]
// var arr2 = arr1

// console.log(arr1 === arr2)  // true
/**
 *  引用数据类型在对比的时候, 对比的是 地址     因为 他们两个的地址完全相同, 所以返回的结果是 true
 */
复制代码
  1. 传参
  • 基本数据类型: 将值拷贝一份传递给形参, 在函数内修改不会影响外界
  • 引用数据类型: 将存储地址赋值给形参, 在函数内修改会影响外界

9.数组的常用方法

  1. push
  • 语法: 数组.push(数据)
  • 作用: 向数组末尾添加数据
  • 返回值: 追加数据后, 数组最新的长度(length)
  1. pop
  • 语法: 数组.pop()
  • 作用: 删除数组最后一条数据
  • 返回值: 被删除的数据
  1. unshift
  • 语法: 数组.unshift(数据)
  • 作用: 向数组开头添加数据
  • 返回值: 添加数据后, 数组最新的长度(length)
  1. shift
  • 语法: 数组.shift()
  • 作用: 删除数组第一条数据
  • 返回值: 被删除的数据
  1. reverse
  • 语法: 数组.reverse()
  • 作用: 反转数组
  • 返回值: 反转后的数组
  1. sort
  • 语法1: 数组.sort()

  • 作用: 会将数据转换为 字符串后, 一位一位的对比

  • 语法2: 数组.sort(function (a, b) {return a - b})

    • 作用: 会按照数字大小升序排列
  • 语法3: 数组.sort(function (a, b) {return b - a})

    • 作用: 会按照数字大小降序排列
    • 返回值: 排序后的数组
  1. splice
  • 语法1: 数组.splice(开始索引, 多少个)

    • 作用: 截取数组部分内容
  • 语法2: 数组.splice(开始索引, 多少个, 插入的数据1, 插入的数据2, 插入的数据3...)

    • 作用: 截取数组部分内容, 并插入新的数据
    • 返回值: 截取出来的部分内容 组成的 数组
  • 数组的方法 能够改变原数组的 就只有上边说的 7 个
  1. slice
  • 语法: 数组.slice(开始索引, 结束索引)

    • 参数:

      • 包前不包后: 包含开始索引位置的数据, 不包含结束索引位置的数据
      • 不写开始索引, 默认是0; 不写 结束索引, 默认是 数组的length
      • 参数支持写负数, 表示倒数第几个, 其实就是 length + 负数
    • 作用: 截取数组部分内容

    • 返回值: 截取出来的部分内容组成的新数组

  1. 面试题: 数组中有两个方法, splice 与 slice, 你能描述一下他们两个的区别吗?
  • 参数含义不同, 然后介绍一下 参数哪里不同
    复制代码
    
  • splice 会改变原数组, 而 slice 不会
    复制代码
    
var arr = [1, 2, 3]
console.log('原始数组: ', arr)

// 1. push
var len = arr.push(500)
console.log(len)    // 4
console.log(arr)    // [1, 2, 3, 500]

// 2. pop
var po = arr.pop()
console.log(po)     // 3
console.log(arr)    // [1, 2]

// 3. unshift
var len = arr.unshift(666)
console.log(len)    // 4
console.log(arr)    // [666, 1, 2, 3]

// 4. shift
var st = arr.shift()
console.log(st)     // 1
console.log(arr)    // [2, 3]

// 5. reverse
var newArr = arr.reverse()
console.log('newArr: ', newArr)
console.log('arr: ', arr)


// 6. sort
var arr = [100, 101, 200, 10, '999', 'qwe', '123abc']
console.log('原始数组: ', arr)

var newArr = arr.sort()
console.log('newArr', newArr)
console.log('arr', arr)

var newArr = arr.sort(function (a, b) {return a - b})
console.log('newArr', newArr)
console.log('arr', arr)

var newArr = arr.sort(function (a, b) { return b - a })
console.log('newArr', newArr)
console.log('arr', arr)

// 7. splice
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
//         0  1  2  3  4  5  6  7  8
console.log('原始数组: ', arr)

// 7.1
var newArr = arr.splice(3, 4)   // 从 下标3 开始截取, 截取 4 个 成员/数据
console.log('newArr', newArr)   // [4, 5, 6, 7]
console.log('arr', arr)         // [1, 2, 3, 8, 9]

// 7.2
var newArr = arr.splice(2, 3, '数据1', '数据2', '数据3', '数据4', '数据5')  // 不管插入多少个数据, 都是从下标2开始的
console.log('newArr', newArr)
console.log('arr', arr)


// 8. slice
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
//         0  1  2  3  4  5  6  7  8
console.log('原始数组: ', arr)

var newArr = arr.slice(3, 4)    // 从 下标3 开始截取, 截取到 下标4
console.log('newArr', newArr)   // [4]
console.log('arr', arr)

var newArr = arr.slice(5)   // 不写 结束索引, 相当于 写了数组.length, 所以这里相当于写了 slice(5, arr.length)
console.log(newArr) // [6, 7, 8, 9]

/**
 *  此时 开始索引与结束索引都没有填写,  那么 开始索引相当于是写了一个 0,    结束索引相当于写了 数组.length
 *
 *      arr.slice()     相当于写了      arr.slice(0, arr.length)
 */
var newArr = arr.slice()
console.log(newArr)

var newArr = arr.slice(3, -2)
console.log(newArr) // [4, 5, 6, 7]
/**
 *  arr.slice(3, -2)
 *      slice 这个方法 允许写 负数
 * 
 *      写负数的时候 就相当于写了 length + 负数
 * 
 *      arr.slice(3, -2)    ->      arr.slice(3, arr.length + (-2))     -> arr.slice(3, arr.length - 2)
 *                                                                      -> arr.slice(3, 9 - 2)
 *                                                                      -> arr.slice(3, 7)
*/
复制代码

10.数组的常用方法2

  1. concat
  • 语法: 原始数组.concat(数组1, 数组2, ...., 数据1, 数据2, ....)

    • 作用: 进行数据拼接, 把数组...数据之类的小括号里的内容, 拼接在原始数组中
    • 返回值: 拼接好的数组
  1. join
  • 语法: 数组.join('连接符')

    • 作用: 使用 "连接符", 把数组内的每一个数据连接成一个字符串 (不写连接符, 默认使用的是 逗号)
    • 返回值: 连接好的字符串
  1. indexOf
  • 语法1: 数组.indexOf(要检查的数据)

    • 作用: 从前到后(从左到右) 检查该数据第一次在该数组内出现 索引
  • 语法2: 数组.indexOf(要检查的数据, 开始索引)

    • 作用: 在开始索引的位置, 按照从左到右的顺序, 检查该数据第一次在该数组内出现的 索引

    • 返回值: 找到数据的情况下, 会将该数据第一次出现的下标(索引)返回

      • 没找到的情况下, 会直接返回一个 -1
      • 备注: 开始索引不写的时候 默认是0
  1. lastIndexOf
  • 语法1: 数组.lastIndexOf(要检查的数据)

    • 作用: 从后向前(从右向左), 检查该数据第一次在该数组内出现的 索引
  • 语法2: 数组.lastIndexOf(要检查的数据, 开始索引)

    • 作用: 在开始索引的位置, 按照从右向左的顺序, 检查该数据第一次在该数组内出现的 索引

    • 返回值: 找到数据的情况下, 返回第一次出现的下标(索引)

      • 没找到的情况下, 直接返回一个 -1
var arr = [1, 1, 2, 2, 3, 3, 0, 4, 0]
//         0  1  2  3  4  5  6  7  8
console.log('原始数组: ', arr)
复制代码
// 9. concat
var newArr = arr.concat([4, 5, 6], [10, 20], ['a', 'b', 'c'], 'qwer')
console.log('newArr', newArr)   // [1, 2, 3, 4, 5, 6, 10, 20, 'a', 'b', 'c', 'qwer']
console.log('arr', arr)

//10. join
var newArr = arr.join() // 不传递连接符, 默认使用的是 逗号连接
var newArr = arr.join('!')  // 使用 ! 将数组内的所有数据拼接成一个 字符串
// console.log(newArr)

// 11. indexOf
var num = arr.indexOf(100) // 此时要检查的数据是 数字100, 但是数组中并没有出现过 数字 100, 所以返回值应该是 -1
var num = arr.indexOf(0) // 此时要检查的数据是 数字0, 数字0按照从左到右的顺序, 第一次出现的下标为 6, 所以返回值应该是 6
var num = arr.indexOf(1) // 此时要检查的数据是 数字1, 数字1按照从左到右的顺序, 第一次出现的下标为 0, 所以返回值应该是 0
var num = arr.indexOf(1, 3) // 此时要检查的数据是 数字1, 但是是从下标3的位置开始按照从左往右的顺序查找, 因为后续并没有数字1, 所以此处应该返回 -1
console.log(num)

// 12. lastIndexOf
var num = arr.lastIndexOf(3)    // 此时按照从右向左的顺序查找, 发现第一次出现的位置是 下标 5 的位置
var num = arr.lastIndexOf(3, 2) // 此时在下标2的位置按照从右向左的顺序查找, 但是此时在数组中后续的位置并没有出现数字3, 所以按照规则, 应该返回 -1
console.log(num)

复制代码

11.数组遍历的常用方法

  1. forEach
  • 语法: 数组.forEach(function (item, index, origin) {})

    • item: 数组的每一项 的值
    • index: 数组的每一项 对应的下标
    • origin: 原始数组 (了解即可, 一般没人用)
  • 作用: 遍历数组

  • 返回值: 该方法永远没有返回值 (undefined)

  1. map
  • 语法: 数组.map(function (item, index, origin) {}) 三个参数的意义与 forEach 相同
  • 作用: 映射数组
  • 返回值: 返回一个和原数组长度相同的数组, 但是内部数据可以经过我们的映射加工
  • 映射加工: 就是在函数内 以 return 的形式书写

有一道面试题: 数组常用的遍历方法中, 有一个forEach 和 一个 map, 这两个方法有什么区别?

    1. forEach 的作用是用来遍历数组, 而 map 的作用是用来映射数组
    1. forEach 没有返回值, 而 map 是可以有返回值的
  1. filter
  • 语法: 数组.filter(function (item, index, origin) {}) 三个参数的意义与 forEach 相同
  • 作用: 过滤数组
  • 返回值: 返回一个新数组, 内部存储的是原始数组过滤出来的部分内容
  • 过滤条件: 过滤条件以 return 的形式书写
  1. find
  • 语法: 数组.find(function (item, index, origin) {}) 三个参数的意义 与 forEach 相同

  • 作用: 在数组内查找满足条件的第一项

  • 返回值: 找到的数据, 如果没找到返回的是 undefined

    • 查找条件以 return 的形式书写
  1. findIndex
  • 语法: 数组.findIndex(function (item, index, origin) {}) 三个参数的意义 与 forEach 相同
  • 作用: 在数组内查找满足条件的第一项 的下标
  • 返回值: 找到的数据 的下标, 如果没找到返回的是 -1
  • 查找条件以 return 的形式书写
  1. some
  • 语法: 数组.some(function (item, index, origin) {}) 三个参数的意义 与 forEach 相同
  • 作用: 判断数组内是否有一个满足条件
  • 返回值: 一个布尔值 true/false
  • 判断条件以 return 的形式书写
  1. every
  • 语法: 数组.every(function (item, index, origin) {}) 三个参数的意义 与 forEach 相同

  • 作用: 判断数组内是否全都满足条件

  • 返回值: 一个布尔值 true/false

    • 判断条件以 return 的形式书写
  1. reduce
  • 语法: 数组.reduce(function (prev, item, index, origin) {}, init)

    • prev: 表示初始值或者上一次的运算结果
    • item: 表示数组的每一项 的值
    • index: 表示数组的每一项 的下标(索引)
    • origin: 原始数组
  • 作用: 用来实现叠加效果

  • 返回值: 最终叠加的结果

  • 注意:

    • 叠加条件以 return 的形式书写
    • prev 第一次的值, 如果你传递了 init, 就是 init 的值, 如果没有传递 init, 那么就是 数组[0] 的值
    • 如果传递了 init, 循环执行 数组.length 次, 如果没有传递 init, 循环执行 数组.length - 1 次
var arr = [100, 200, 300, 400, 500, 600]
console.log('原始数组: ', arr)

//1. forEach
arr.forEach(function (item, index, origin) {
    console.log(item, index)
    console.log(origin)
})

//2. map
var newArr = arr.map(function (item, index, origin) {
    // console.log(item, index, origin)
    return item * 2
})
var newArr = arr.map(function (item) {
    return item * 2
})
console.log('映射出来的数组: ', newArr)

//3. filter
var newArr = arr.filter(function (item, index, origin) {
    return item > 350   // 过滤数组的内容, 只留下 item 大于 350 的成员
})
console.log(newArr)

//4. find
var newArr1 = arr.find(function (item, index, origin) {
    return item > 3500   // 在数组中查找第一个符合条件的成员
})
console.log(newArr1)

//5. findIndex
var newArr2 = arr.findIndex(function (item, index, origin) {
    return item > 3500
})
console.log(newArr2)




var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log('原始数组: ', arr)

//6. some
var bo1 = arr.some(function (item, index, origin) {
    // return item % 2 === 0   // 判断数组内是否有  一个  满足条件的
    return item > 500   // 判断数组内是否有 一个 满足条件的
})
console.log(bo1)    // true / false


//7. every
var bo2 = arr.every(function (item, index, origin) {
    // return item % 2 === 0   // 判断数组内 是否  全都    满足条件
    return item > 0     // 判断数组内 是否  全都    满足条件
})
console.log(bo2)

var arr = [1, 2, 3, 4]
console.log('原始数组: ', arr)


// 8. reduce
var str = arr.reduce(function (prev, item, index, origin) {
    return prev + item
}, 0)
console.log(str)    // 10
复制代码

12.数组塌陷

13.数学方法

在 JS 中 Math 对象给我们提供了操作数据的一些方法(数学的方法)

  1. random
  • 语法: Math.random()
  • 作用: 得到一个随机数, 每次生成的数字都不一样, 但一定是0~1之间的, 包含0, 不包含1, 也就是说最大值可能是 0.99999....
  1. round
  • 语法: Math.round(数字)
  • 作用: 将这个数字(小数), 按照四舍五入的形式变成整数
  1. ceil
  • 语法: Math.ceil(数字)
  • 作用: 将这个数字(小数) 向上取整
  1. floor
  • 语法: Math.floor(数字)
  • 作用: 将这个数字(小数) 向下取整
  1. abs
  • 语法: Math.abs(数字)
  • 作用: 返回这个数字的绝对值
  1. sqrt
  • 语法: Math.sqrt(数字)
  • 作用: 求 平方根、
  1. pow
  • 语法: Math.pow(基数, 幂)
  • 作用: 返回基数的几次幂
  1. max
  • 语法: Math.max(数字1, 数字2, 数字3...)
  • 作用: 返回传入的数字中 最大的哪一个
  1. min
  • 语法: Math.min(数字1, 数字2, 数字3...)
  • 作用: 返回传入的数字中 最小的哪一个
  1. PI
  • 语法: Math.PI
  • 作用: 返回 π

14.JS的严格模式

  • JS 是一个相对不是很严谨的语言, 在开发的时候一些代码也不是很严格
  • 换句话说严格模式就是对开发的时候, 你写的代码做了一些要求
  • 严格模式的规则
  1. 声明变量必须要 var 关键字
  2. 函数的形参不可以重复
  • JS 中默认是没有开启严格模式, 如果想要开启严格模式, 需要手动在代码最开始的位置(script标签内第一行), 写一个字符串 'use strict'
  • 现在的公司的项目中, 基本都是按照严格模式开发的

15.字符集(了解)

  • 计算机只能存储二进制数据 0101010

  • 我们的 大写字母 小写字母 符号之类的内容 都是由 二进制数字组成

  • 或者说我们在敲一个字符的时候, 都有一个对应的编号, 计算机存储的时候存储的是这些编号,

  • 只不过我们看到的时候, 是通过这些编号解析成我们看到的内容

  • 前身: ASCII as key (128) 只够 美国人用英语的使用

  • 国内 推出了一个属于中国的 GBK 国标码 前128位 ASCII码, 后边从129位开始就是汉字

  • unicode (万国码)

    • 前 128 位还是 ASCII码, 后边开始是各个国家的文字码
    • 八位十六进制编码 容量小, 但是占用内存也小 UTF-8
  • 十六位的十六进制编码 容量大, 但是占用内存也大