ES6读书笔记汇总系列一

12次阅读

共计 14239 个字符,预计需要花费 36 分钟才能阅读完成。

前言

温故而知新, 可以为师矣. 相信大家都会有这种感觉, 很多学过的知识经常不使用就会慢慢遗忘!!! 本文把以前自己关于 ES6 的入门读书笔记重新汇总了一下, 并结合了工作中常用的使用场景 …

变量声明方式 let,const

ES5 中声明变量: 
    a. var 命令会发生”变量提升“现象,即变量可以在声明之前使用,值为 undefined。b. es5 中变量只有两种作用域: 全局 和 局部(函数内声明); 全局和局部都有变量提升现象; 先提前, 再进行赋值.
    不合理场景 1: 局部内层变量 可能覆盖掉 全局变量
    不合理场景 2: for 循环中 用 var 声明的 变量 i; 会泄露成全局变量, 循环结束并没有消失

ES6 中声明变量:
1. 声明的变量 a 的作用域为块级, 并且只在自己所在的块级作用域起作用; 外层作用域不能访问内层, 内层可以访问外层的;
2. 内 && 外层的同名变量互不干扰; 内层重新赋值也不会对外层造成影响;
3. 变量必须先声明, 再使用, 否则报错...(暂时性死区特性), 没有所谓的变量提升
4. 同一作用域不能重复声明同一个变量; 函数 function 第一层作用域变量声明不能和形参一样; 否则报错

// 注意:
1. es6 中, 变量在 for 循环中的使用
    每一轮的 i 值 只在当前的循环中有效; 相当于每一次循环 i 都是一个新变量 
    // 1. 循环变量在设置的时候是: 一个父作用域
    // 2. 循环体内部又是一个单独的子作用域
    // 3. 所以当同时两个块级作用域如使用相同的变量 i, 循环体内部会使用自己作用域声明的 i

2.ES6 规定,块级作用域之中,函数声明语句的行为类似于 let,在块级作用域之外不可引用。// 1. 避免在块级作用域内使用函数时声明的方式 (function fn(){xxx}) 声明函数
    // 2. 可以使用表达式方式 let f = function(){}
    // 也就是外层无法调用内层声明的函数...

3.const 声明一个常量: 该变量不能变化, 是一个恒定值
    const NUM_100 = 100; // 定义时就需要初始化
    // const 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。// 值类型:   数据就 等同于 这个常量的地址的值
    // 引用类型: 这个常量 是一直指向一个固定的地址, 不能变的(修改指向就保错, 即赋值操作); 只不过对象本身可变

变量的解构赋值语法

解构赋值, 我按照字面意思就是 解析数据结构, 然后给一一对应的变量进行赋值的一种语法

  • 解构的语法:

    = 号左边是: 匹配模式; = 号右边是: 实际的数据(或者数据对应的变量);
    
    解构的结果:
       解构成功: 左边变量的值 就是右边对应变量的值
       解构不成功: 即没有对应值匹配, 变量的值变为 undefined
       不完全解构: 左边的模式之匹配到右边数组的一部分
  • 变量是复杂数据类型(数组, 对象)

    1. 数组解构赋值
      1. 右边的值需要能够被遍历 
      2. 允许左边给默认值: let [x=1, y=x] = ['xxxx'];
      3. 支持嵌套结构的 解构赋值
     注意:
      let [x, y=true] = ['xxxx']; // 右边数组对应成员要 === undefined
      // console.log(x,y); // 如果是 null, 则默认值不会生效;
      // 如果右边 不是 undefined, 则左边 会取到值
    
    2. 对象的解构赋值
      1. 对象本身就是无序的, 是根据左右同名变量 来做赋值操作, 匹配规则和数组类似
      // 对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者
      例: let {foo: foo, bar: bar} = {foo: "aaa", bar: "bbb"};
      2. 持嵌套结构的 解构赋值
          let obj = {};
          let arr = [];
          ({foo: obj.num, bool: arr[0]} = {foo: 123, bool: true}); // 圆括号
          console.log(obj, arr);
    
    3. 对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量, 几个例子
      3-1 let {sin, cos} = Math; // 将 math 对象中方法给对象
      3-2 取出数组的首尾 2 项
          let list = [1,2,323,123,12,2];
          let {0: first, [list.length-1]: last} = list;
  • 变量是简单数据类型(字符串, 数值, 布尔值)

    1. 字符串的解构赋值
      字符串被转换成了一个类似数组的对象: 可以理解未伪数组
      let [a,b,c,d,e] = 'hello'; // 每个变量对应一个字符
    
    2. 数值和布尔值的解构赋值
      解构赋值的规则: 只要等号右边的值不是对象或数组,就先将其转为对象。由于 undefined 和 null 无法转为对象,所以对它们进行解构赋值,都会报错
      所以, 数值和布尔值会先转成其包装对象 Number 和 Boolean 对象; 然后可以赋值对象的属性
  • 函数参数的解构

    1. 会将实参与形参一一对应
    console.log([[1, 2], [3, 4]].map(([a, b]) => a + b));
  • 常用的使用场景

       变量之间值的交换; 函数中传参和接受返回值(对象的方式); 对象遍历等等...
       
       1. 交换变量的值
       let v100 = 100;
       let v1 = 1;
    
       [v1, v100] = [v100, v1];
       console.log(v1, v100);
    
       2. 接受函数的多个返回值: 比如数组, 对象
       // 函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。// 有了解构赋值,取出这些值就非常方便。function example() {return [1, 2, 3];
       }
       // let [a, b, c] = example();
    
       3. 函数传参
       // 解构赋值可以方便地将一组参数与变量名对应起来
       // 参数是一组有次序的值
       function f([x, y, z]) { }
       f([1, 2, 3]);
    
       // 参数是一组无次序的值
       function f({x, y, z}) { }
       f({z: 3, y: 2, x: 1});
    
       4.json 数据的处理
       // 解构赋值对提取 JSON 对象中的数据,尤其有用。let jsonData = {
           id: 42,
           status: "OK",
           data: [867, 5309]
       };
    
       let {id, status, data: arr1} = jsonData;
       console.log(id, status, arr1);
    
       5. 设置函数参数的默认值
       // 避免了在函数体内部再写 var foo = config.foo || 'default foo';
       // 在传参时; 特别是传一个对象参数时, 可以事先配置好参数的默认值
       // func({参数 1 = true, 参数 2 = false, ...} = {外部实参没有传值的就是用默认值}){}
    
       6. 遍历 Map 结构
       // 可迭代对象, 都可以用 for...of 来遍历
       const map = new Map();
       map.set('first', 'hello');
       map.set('second', 'world');
    
       for (let [key, value] of map) {console.log(key + "is" + value);
       }
       // 获取键名
       for (let [key] of map) {console.log(key);
       }
       // 获取键值
       for (let [,value] of map) {console.log(value);
       }
    
       7. 模块导入
       // 加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰
       // const {SourceMapConsumer, SourceNode} = require("source-map"); 
       

字符串, 数组, 对象的扩展

字符串方法

1. 处理 4 个字节存储的单个字符
// 测试一个字符由两个字节还是由四个字节组成的最简单方法 (Unicode 编号大于 0xFFFF)
// codePointAt(下标): 返回 10 机制字节码;
function is_32bit(char) {return char.codePointAt(0) > 0xFFFF;
}
console.log(is_32bit('????a')); // true
// 识别 4 个字节 (32 位) 组成的单个字符
console.log(String.fromCodePoint(0x20BB7)); // ???? 

2. 字符串的遍历 for of
let text = '我的名字';
for (const char of text) {console.log(char);
}

3. 确定一个字符串中是否包含另一个目标字符串
// includes(), startsWith(), endsWith() // 返回 true 和 false
console.log(text.startsWith('我'));
console.log(text.endsWith('我'));
console.log(text.includes('我'));

4.repeat(num); 将字符串重复 num 次并返回
console.log(text.repeat(3));

5. 字符串补全长度的功能
// padStart()用于头部补全,padEnd()用于尾部补全
// 参数 1: 补全后的生效长度; 参数 2: 用于补全的字符串(没有参数默认空格)
// 长度过了; 会截取超出位数的字符串
// 长度 <= 原长度; 返回自己

// 用途 1: 将数值补全为指定位数
console.log("1".padStart(10, '0')); // 0000000001
// 场景 2: 日期补全
console.log('09-12'.padStart(10, '2018-MM-DD')); // 2018-09-12

模板字符串

模板字符串: 反引号 ` 标识; 
// 变量名使用 ${变量名}; 可以省去字符串的拼接了
let name = "bob";
let age = 24;
console.log(`Hello ${name}, how are you ${age}?`);

// ${这里面可以进行运算; 函数调用; 放对象的属性等}; 相当于执行 js 代码
// 还可以相互嵌套

当然, 模板字符串的用法比较复杂, 后续再深入总结

数值类型方法

// 1. 检查数字为有限值
Number.isFinite(12); // true; 其他类型都为 false

// 2. 检查数值是不是 NAN
Number.isNaN(1+NaN); // true; NaN 数值与非数值运算的结果 NaN

// 3.Number.parseFloat 和 Number.parseInt; 将 ES5 的全局方法移到 Number 对象上

// 4.Number.EPSILON * Math.pow(2, 2): 两个浮点数之间的最小误差; 
// 差值小于它, 就可以认为时相等

// 5.Math 方法的扩展
console.log(Math.round(4.5)); // 5; 四舍五入

// Math.trunc 方法用于去除一个数 (正负都可以) 的小数部分,返回整数部分。console.log(Math.trunc(3.1)); 
// 兼容性写法
// Math.trunc = Math.trunc || function(x) {//     return x < 0 ? Math.ceil(x) : Math.floor(x);
//  };

// Math.sign()
// 判断正负, 还是 0; 对非数值, 能转化的转化; 不能转的就是 NaN
// 返回值: 正 +1; 负 -1; 0; -0; 其他值 NaN

数组的扩展方法

ES6 中会将数组空位转为 undefined

1.Array.from(param1, param2)方法用于将两类对象转为真正的数组:参数 1: 一个对象 ==> 伪数组对象和可遍历(iterable)的对象
    参数 2: 回调函数 ==> 类似于数组的 map 方法,对每个元素进行处理,将处理后的值放入返回的数组。return 值: 一个数组;
示例:
    let arrayLike = {
        '0': 'a',
        '1': 'b',
        '2': 'c',
        length: 3
        // 0: 'a',
        // 1: 'b',
        // 2: 'c',
        // length: 3
    };
    let real_arr = Array.from(arrayLike);

2.Array.of(传一组数值); 用于将一组值,转换为数组。弥补了构造函数 Array()传数值的缺点
    参数: 一组数值, 如: 1,2,3,4...
    return 值: 一个数组

3. 实例方法

    3.1 arr.find(): 类似过滤函数 filter(function(value, index, arr))
        使用: 传入一个回调函数, 返回第一个符合要求的成员
        示例: var res = [1,2,3,4,-100].find(n => n < 0); // -100

    3.2 arr.findIndex(): 同上, 只不过是返回第一个符合条件的数组成员的位置
        注意: 第二个参数是传一个对象,回调函数中若使用了 this, 则指向这个对象

    3.3 arr.includes(): 判断数组中是否包含我们给定的值; 这样以后就不用 indexOf 了

    3.4 实例数组的遍历方法: entries(),keys() 和 values() 用于遍历数组 返回一个遍历器对象
            // keys()是对键名的遍历:   对应索引
            // values()是对键值的遍历: 对应值
            // entries()是对键值对的遍历: 索引 + 值

4. 数组扩展方法 [a, b, c]
    map 映射, reduce 汇总, filter 过滤, forEach 迭代

    1. map: 一个映射一个 
    // [100, 59, 22] => [及格, 不及格, 不及格]

    let score = [100, 59, 22];
    let res = score.map(item => item>60? '及格':'不及格');console.log(res);

    2. reduce: 一堆变成一个

    // temp 为中间结果; 如果不设置, 则为第一个下标为 0 的数
    let res1 = score.reduce(function(temp, item, index, arr) {if (index != arr.length - 1) {return item + temp;} else {return (temp + item) / arr.length;
        }
    }); 
    console.log(res1);

    3.filter: 保留我想要的结果
    let res2 = score.filter(item => item%11!=0);
    console.log(res2);

    4.forEach: 只是操作一下每一项; 返回值为 undefined
    let arr = [1,2,3,4]
    arr.forEach(function (item, index, arr) {
        // 这里可以用外部变量接受 这里面操作的值
        console.log(index +':'+ item);
    });
    console.log(res3); // undefined

对象的扩展

这里主要介绍一下对象的多种遍历方法; 其他内容在扩展运算符 … 中总结.

1.for...in
    for...in 循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。2.Object.keys(obj),values(obj),entries(obj)
    返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名, 值, 键值对。3.Object.getOwnPropertyNames(obj)
    返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。4.Object.getOwnPropertySymbols(obj)
    返回一个数组,包含对象自身的所有 Symbol 属性的键名。5.Reflect.ownKeys(obj)
    返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

扩展运算符 …

1. 扩展运算符是什么?
    扩展运算符用三个点... 表示: 相当于函数 rest 参数的逆运算, 可以将数组, 对象中的成员序列化出来
    我这里暂且把它理解为一种运算符吧, 用来解析各种数据类型的成员

2. 扩展运算符的使用场景?
    2.1 将数组成员转为一个逗号分隔的参数序列:
        这样调用一些数组的 API 时; 可以直接传一个...arr 进去, 省去了传参的麻烦
        例 1: console.log(...[1,2,3]); // 1 2 3
        例 2: var date = new Date(...[2015, 01, 01]); 
            console.log(date); // 2015-01-31T16:00:00.000Z

    2.2 取代 apply 方法: 
        // ES5 的写法
        let max1 = Math.max.apply(null, [14, 3, 77]);
        // ES6 的写法
        let max2 = Math.max(...[14, 3, 77]);

    2.3 数组的深拷贝: 将对象全部拷贝一份, 是一个独立的内存空间
        let arr1 = [0, 1], arr2 = [...arr1]; // 用变量去接受经过扩展运算符运算的数组
        arr1[0] = 100; // 修改数组 arr1
        console.log(arr1); // [100, 1] 发送改变
        console.log(arr2); // [0, 1]   未改变

    2.4 数组的合并
        注意: 合并操作是浅拷贝: 是对数组中对象成员的引用
        浅拷贝: (分为简单数据类型引用: 修改数据另一个不会变; 复杂数据类型引用: 修改后会改变)
        arr3 = [...arr1, ...arr2]; // 此时 arr3 为一个新数组; [100, 1, 0, 1], 因为内部成员都是数值,
        所以修改了 arr1 或者 arr2 中的元素也不会变

        那么, 如果数组中成员是对象; 则会改变成员属性, 合并生成的数组成员也会变
        const a1 = [{foo: 1}];
        const a2 = [{bar: 2}];
        const a3 = [...a1, ...a2];

        console.log(a3); // [{ foo: 1}, {bar: 2} ]
        a1[0].foo = 100;
        console.log(a3); // [{ foo: 100}, {bar: 2} ]

    2.5 可以和变量的解构赋值一起使用; 右边是对象也是可以的
        let [first, second, ...rest] = [1,2,3,4,5,6];
        console.log(first); // 1
        console.log(second); // 2
        console.log(rest); // [3,4,5,6]

    2.6 还有与 Array.from()方法类似的作用, 将 类似数组的对象和可迭代对象 转为真数组
        console.log([...'hello']); // ["h", "e", "l", "l", "o"]
        注意: 如果涉及到操作四个字节的 Unicode 字符的函数; 可以使用[...string], ... 能够识别;

    2.7 扩展运算符在对象中的使用
        // 解构赋值, 如果右边数据是 undefined 或 null 则解构会失败
        let {x, y, ...z} = {x: 1, y: 2, a: 3, b: 4}; // x,1; y,2; z,{a:3, b:4}

        // 注意: 如果扩展运算符后面不是对象,则会自动将其转为对象。{...1}, {...true}, {...undefined}, {...null} 都会转为 空对象{}

函数扩展

函数参数设置默认值

语法: function(x= 默认值 x, y= 默认值 y); 当然也可以使用解构赋值, 使用对象的形式设置,({x=xxx, y=yyy})
默认值参数放在括号尾部

1. ES5 中设置默认值的方式

    function fn1(x, y) {
        y = y || "world"; // ES5 中, 在函数体内赋值一个默认值
        console.log(x, y);
    }
    fn1('hello'); // hello world
    fn1('hello', 'bob'); // hello bob
    fn1('hello', ''); // 传空值时也使用默认值
    fn1('hello', false); // 传 false 时也使用默认值

// ES6 中 直接给 () 中参数赋默认值, 相当于初始化形参, 函数体内不允许 let 和 const 再次声明
// ES6 中会事先对参数 y 进行类型判断: typeof y === 'undefined'; 是才给默认值

    function fn2(x, y = 'ES6') {console.log(x, y);
    }
    fn2('learning'); //learning ES6 
    fn2('learning', ''); //learning 空也能输出
    fn2('learning', false); //learning false 布尔值也可以

2. 构造函数中用来初始化 函数的属性 function Person(name='bob') {this.name = name};
    也是可以直接在 () 中传默认值的

3. 解构赋值形式给函数传参
例 1:
    function fn3({x, y = 100}) {
        // 函数的形参接受一个对象; 函数传值也要传一个对象;
        console.log(x, y);
    };

    // ES5 中我们是传一个对象, 然后再定义变量 保存 对象中对应的属性值
    // ES6 可以直接在形参中 去接受对应的属性值
    fn3({}); // undefined 100; 
    fn3();  // 保错
例 2:
    // 下面我们重写一下, 注意::: 这种方式的传参是设置了对象解构赋值的默认值为空对象, 这样直接调用便不会报错
    function fn4 ({x, y = 101} = {}) {
    // 不传值的情况下: 给函数一个默认参数: 空对象
    console.log(x, y);
    };
    fn4(); //undefined 101; 相当于 fn4({});

4. 默认参数的作用域
    函数 () 中式一个单独的作用域, ES6 中函数体中的运算会先去 () 中找对应的变量进行运算

rest 参数

ES6 引入 rest 参数(形式为... 变量名),用于获取函数的多余参数,这样就不需要使用 arguments 对象了。rest 参数搭配的变量是一个数组,参数都放在这个数组中。要使用的话, 直接在函数体中遍历即可, 当然...rest 放在 () 尾部

    举个栗子:
        function add (...number) {
            let sum = 0;
            // number 变量相当于一个存放形参的数组
            // 可以使用数组的方法, 也就是说, 我们可以当作数组来操作这个参数 number
            // 基本方法 和 迭代方法都能使用
            for (let num of number) {sum += num;}
            return sum;
        } 
        console.log(add(1,2,3,4,5)); // 15

箭头函数 () => {}

1. 箭头函数基本语法: 
    var 变量指向这个函数 = (参数 1, 参数 2...) => {函数体大于一行时用大括号} 

理解: ES6 中箭头函数 相当于函数的简写, 省略了 function 关键字, 只有一个参数时还可以省略()
    箭头左边是 (参数) => 箭头右边是函数体(一行代码可以省略大括号, 直接写返回值表达式) 
    // 如果返回的是一个对象则加括号({对象})

2. 常用的使用场景
    2.1 回调函数的简化
        // 比如数组常用的迭代方法 map: 常规方法是 传入一个回调函数 function(x) {return x**2};
        var arr1 = [1,2,5,3,6,0];
        var result1 = arr1.map(x => x**2);
        // 排序
        var result2 = arr1.sort((a, b) => a - b); // [0,1,2,3,5,6]
        // 箭头函数传 rest 参数
        let arr3 = (...numbers) => numbers; // 自动将参数序列转为数组

    2.2 嵌套使用; 函数式编程
        例如: 要实现将一个值 插入到数组 某个值的后面, 然后返回一个新数组
        function insert (value) {return {into: function (array) {return {after: function (after_value) {
                    // 起始位, 要删除的项, 替换项
                    array.splice(array.indexOf(after_value) + 1, 0, value);
                    return array;
                }}
            }}
        }

        // 用箭头函数实现; 简化了很多
        // 声明一个变量指向函数; 不要忘记对象用 () 包起来
        var insert = (value) => ({into: (array) => ({after: (after_value) => {array.splice(array.indexOf(after_value) + 1, 0, value);
            return array;
        }})});

        var res = insert(100).into([1, 2, 3]).after(2);
        console.log(res); // [1, 2, 100, 3]

3. 箭头函数注意事项; 

    1.this 对象 ==> 指向定义时的对象, 而不是谁调用就指向谁了; 相当于固定了 this 指向
        箭头函数根本没有自己的 this,导致内部的 this 就是外层代码块的 this
        箭头函数中的 this 相当于 ES5 中 引用了外层函数的 this; 在外层函数用 var _this = this; 然后在箭头函数中使用

    2. 箭头函数不能当作构造函数, 不能使用 new 去声明
    3. 没有 arguments 对象了, 使用 rest 参数替代
    4. 不能使用 yield, 不可以作为生成器函数

函数的尾调用

函数的尾调用优化
function f(x){return g(x);
    // 函数 f 的最后一步是 调用函数 g,这就叫尾调用。}
function f(x){g(x);
    // 函数没有明确返回值, 默认回返回 undefined; 所以不是尾调用
    return undefined;
}

优化思路: 用内层函数的调用帧,取代外层函数的调用帧(保存了函数调用后的信息)
         相当于可以不用调用外层函数
注意:
    只有不再用到外层函数的内部变量,内层函数的调用帧才会取代外层函数的调用帧,否则就无法进行“尾调用优化”。尾递归优化
思路: 把所有用到的内部变量改写成函数的参数
    1. 参数设置成默认值的方式;  
    2. 函数柯里化 currying; 意思是将多参数的函数转换成单参数的形式
function Fibonacci (n , ac1 = 1 , ac2 = 1) {if( n <= 1) {return ac2};
    // 尾部调用自身; 并且参数中保存了上一次调用帧; 节省内存
    return Fibonacci (n - 1, ac2, ac1 + ac2);
}

console.log(Fibonacci(100)); 
// 注意:
// ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。

Set 和 Map 数据结构

set

Set 数据结构: 可以理解为没有重复成员的一个类似数组的对象; 就叫集合吧
结构形式: {1, 2, 3, 4}

使用方法:
// 使用构造函数 Set; 参数为一个可遍历的对象
const set = new Set([1,2,3,4]); // 实例化一个 set; set 结构是可迭代的对象
// 返沪值: {1, 2, 3, 4}

Set 的属性和方法

1. size: 返回 set 集合的大小, 即成员个数

2. Set 的增删查
// add(value):添加某个值,返回 Set 结构本身。// delete(value):删除某个值,返回一个布尔值,表示删除是否成功。// has(value):返回一个布尔值,表示该值是否为 Set 的成员。// clear():清除所有成员,没有返回值。3. Set 遍历成员; Set 的遍历顺序就是插入顺序。// keys():返回键名的遍历器
// values():返回键值的遍历器
// entries():返回键值对的遍历器
// forEach():使用回调函数遍历每个成员, 回调参数为键值和 set 自身

使用场景:

Set 作为一种数据结构, 主要用来存放数据, 并且内部成员不重复; 我们可以利用它的这个特性来做一些事.
1. 比如去重
    let arr = [1,2,2,3,1,1,14];
    let str = 'dsadaedwdwa';
    console.log([...new Set(arr)]);
    console.log([...new Set(str)].join());

Map

其实 Map 有点类似 python 中的字典结构;
ES6 中 Map 类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
也就是说,Object 结构提供了“字符串: 值”的对应,Map 结构提供了“值 => 值”的对应

结构形式: Map: {[ 1, 2, 3] => ‘ 数组 ’, ‘name’ => {name: ‘bob’} }

使用方法:
使用构造函数 Map 进行实例化; 参数为双元素的可迭代对象(能够调用 next 方法的对象)

const newMap = new Map([['name', 'Blob'], ['age', 24]]);
// 也可实例化一个空 map 对象, 通过 set(值 1, 值 2)方法去添加成员

Map 的属性和方法: 基本与上面的 Set 一致

1.Map 的增删查
// set(key1, value1):添加一个键值对
// get(key); 获取某个键值对
// delete(key):删除某个键值对
// has(key):返回一个布尔值,表示该值是否为 Map 的成员。// clear():清除所有成员,没有返回值。

常用场景:

可以使用扩展运算符...Map 可以实现与数组, 对象,json 对象的互转;
我们定义固定格式的数据时可以使用, 也可以用来简化判断语句
#  set 中来判断 code
const NEED_LOGIN_CODE_SET = new Set([10007,100011])
if (NEED_LOGIN_CODE_SET.has(code)) { }
# map 取值
let buildEnv = process.env.VUE_APP_ENV
const K_V = [['development', 'address1'],
    ['test', 'address2'],
    ['production', 'address3']
]
const URL_MAP = new Map(K_V)
export default URL_MAP.get(buildEnv)

for…of

for…of 是 ES6 新增的语法; 用来遍历具有 Iterator 接口的对象; 这种对象有 next()方法,\
可以对自身进行遍历, 每一次调用便返回对应的值 …

for…of 循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如 arguments 对象、DOM NodeList 对象)、Generator 对象,以及字符串。

class 关键字: 类

  • ES5 中的类实现

    // ES5 中对象实例化的方法: 通过构造函数实例化

      function Func(x, y) {
          this.x = x;
          this.y = y;
      }
      // 给构造函数的原型添加属性
      Func.prototype.toString = function() {
          // 把对象转为字符串
          return '(' + this.x + ',' + this.y + ')';
      }
      // 实例化一个对象
      var f = new Func(1,100);
      console.log(f.toString());
    
  • ES6 的类实现

      // ES6 中 通 class 来定义类; 其实就是构造函数的改写, 是 js 的语法更像后台语言
      class Func1 {
          // 构造实例对象的方法; 相当于初始化
          constructor(x, y) {
              this.x = x;
              this.y = y;
          }
    
          // 添加类方法: toString()方法
          toString() {return '(' + this.x + ',' + this.y + ')';
          }
      }
    
      // 类: 就是一个函数, 本身为一个构造函数; 也是通过 new 来实例化一个对象
      console.log(typeof Func1);
      console.log(Func1 === Func1.prototype.constructor); 
      let f1 = new Func1();
      console.log(f1.__proto__.constructor); // 省略了__proto__
    
      // 类的方法都定义在 prototype 对象上
    
  • ES6 中的继承

      // ES6 面向对象写法: class 替换 构造函数
    
      class User {
          // 构造器, 初始化
          constructor(name, pass) {
              this.name = name;
              this.pass = pass;
          }
          // 添加方法和属性
          showName() {console.log(this.name);
          }
    
          showPass() {console.log(this.pass);
          }
    
      }
    
      // 在继承 和 封装上的优势;  扩展性强...;  不用从 0 开始;; 可以使用前人造好的轮子
      // 继承超类的属性和方法
          class VipUser extends User {
              // 子类的初始化
              constructor(level, ...args) {// 相当于调用父类的 constructor(name, pass)
                  super(...args); 
                  // super 作为函数调用时,代表父类的构造函数
                  // super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。this.level = level;
              }
              // 方法
              showLevel() {console.log(this.level);
              }
          }
          let vip = new VipUser(77, 'huhua', '123'); // 实例化
          vip.showLevel();
          vip.showName();
          vip.showPass();
    
          // 面向对象中类的应用实例
          // 比如一个组件: 就是一个 class 继承一个组件
          // JSX: == babel;  browser.js
    

json 简写模式

// 1.JSON 对象: 两个方法

let json = {"name": '哈哈', "sex": "女"}; // json 对象键值必须是双引号
let str1 = 'http://www.baidu.com?data=' + encodeURIComponent(JSON.stringify(json)) ; // JSON 对象转为 json 字符串
console.log(str1);

let str2 = JSON.parse('{"a": 12,"b":"hello world"}');
console.log(str2); // JSON 字符串 转为 对象
console.log(str2.a);

// 2.JSON 简写
// 简写:  如果 key 值和 value 是一样的; 直接写一个就可以了...
// 可以省略一个 funcion; 即 success: function(obj) {}  ==> 可以写成 success(obj){}

模块化加载方式

这里说两种常用的模块加载方式

    - commonJS 模块
        CommonJS 模块就是对象,输入时必须查找对象属性
        导出: 
            module.exports = {m1: 'xxx', m2: function(){}}
        导入: 
            const {m1, m2} = require('模块名')
        模块输出的是一个值的拷贝: 如果输出一个值,模块内部的变化就影响不到这个值
        模块是运行时加载(整个对象全部加载)
        
    - ES6 模块化
        export 导出模块: 
            默认导出:export default Person(导入时可任意命名)
            单独导出:export const name = 'xxoo'
            按需导出:export {age, name, sex} 前提是得先定义好
            改名导出:export {name as newName}
        import 导入模块:默认导入:import Person from "person"
            整体导入:import * as Person from "person"
            按需导入:import {age, name, sex} from "person"
            改名导入:import {name as newName} from "person"
            自执行导入:import "person"
            复合导入:import Person, {name} from "person"
        ES6 模块是编译时输出接口(按需导入)
        ES6 模块输出的是值的引用, 即动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块
        如果原始模块的变量变化, 就会影响引入了这个变量的模块中的值

未完待续 …

正文完
 0