21

前言

温故而知新,可以为师矣. 相信大家都会有这种感觉,很多学过的知识经常不使用就会慢慢遗忘!!!本文把以前自己关于 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 模块输出的是值的引用, 即动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块
        如果原始模块的变量变化,就会影响引入了这个变量的模块中的值

未完待续...


a_dodo
2.4k 声望1k 粉丝

天下事有难易乎?