【呕心整理】ES6入门基础,包含运行代码

ES6入门基础

推荐书籍 《ECMAScript 6 入门》:http://es6.ruanyifeng.com/

码云仓库代码(欢迎Start)

码云仓库代码-https://gitee.com/hongjunyong/es6-imooc-lottery

1、为什么要学习ES6

detail.png

1.1、对象拷贝

copy.png

1.2、参数传递

data.png

1.3、更多特性:解构赋值、箭头函数、set和map、异步操作、类与对象、模块化

2、项目构建(略)

    // -e要使用ejs模版引擎 .当前目录执行
    express -e .

express.png

    // 安装依赖:npm install
    
    npm install gulp gulp-if gulp-concat webpack webpack-stream vinyl-named gulp-livereload gulp-plumber gulp-rename gulp-uglify gulp-util y
    args --save-dev
    
    项目运行 gulp --watch

3、ES6语法

3.1、let const命令(案例:lesson1-let-const.js)

3.1.1、let的生命周期
    // i在for循环外面依旧有效
    for(var i=1;i<3;i++){
        console.log(i);
    }
    console.log(i);

    // i只有在for循环里面有效,出了括号生命周期结束
    for(let i=1;i<3;i++){
        console.log(i);
    }
    console.log(i);

let.png

3.1.2、let变量不能重复定义
    错误:
        let a = 1;
        let a = 2;
3.1.3、const常量不能修改,对象可以修改(指针),且声明的时候必须赋值
    const常量不能修改
        错误:
            const a = 1;
            a = 2;

    对象可以修改
        正确:
            const k = {
                a:1
            }
            k.b = 3;
    
    声明的时候必须赋值
        错误:
            const a;
            a = 1;
        正确:
            const a = 1;
3.1.4、es6开启严格模式(‘use strict’)
3.1.4.1 不允许使用未声明的变量
    "use strict";
    x = 3.14;                // 报错 (x 未定义)
3.1.4.2 不允许使用未声明的变量(对象也是一个变量)
    "use strict";
    x = { p1: 10,  p2: 20 };      // 报错 (x 未定义)
3.1.4.3 不允许删除变量或对象
    "use strict";
    var x = 3.14;
    delete x;                // 报错
3.1.4.4 不允许删除函数
    "use strict";
    function x(p1, p2) {}; 
    delete x;                // 报错
3.1.4.5 不允许变量重名
    "use strict";
    function x(p1, p1) {};   // 报错
3.1.4.6 不允许使用八进制
    "use strict";
    var x = 010;             // 报错
3.1.4.7 不允许使用转义字符
    "use strict";
    var x = \010;            // 报错
3.1.4.8 不允许对只读属性赋值
    "use strict";
    var obj = {};
    Object.defineProperty(obj, "x", {value:1, writable:false});
    console.log(obj);		 // 输出{x: 1}
    obj.x = 3.14;            // 报错
3.1.4.9 不允许对一个使用getter方法读取的属性进行赋值
    "use strict";
    var obj = {get x() {return 0} };
    obj.x = 3.14;            // 报错
3.1.4.10 不允许删除一个不允许删除的属性
    "use strict";
    delete Object.prototype; // 报错
3.1.4.11 变量名不能使用 “eval” 字符串
    "use strict";
    var eval = 3.14;         // 报错
3.1.4.12 变量名不能使用 “arguments” 字符串:
    "use strict";
    var arguments = 3.14;    // 报错
3.1.4.13 全局的’use strict’,函数内的变量也声明
    "use strict";
    myFunction();
    
    function myFunction() {
        y = 3.14;   // 报错 (y 未定义)
    }
3.1.4.14 函数内部声明是局部作用域 (只在函数内使用严格模式):
    x = 3.14;       // 不报错 
    myFunction();
    
    function myFunction() {
       "use strict";
        y = 3.14;   // 报错 (y 未定义)
    }
3.1.4.4 为什么使用严格模式:
消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
消除代码运行的一些不安全之处,保证代码运行的安全;
提高编译器效率,增加运行速度;
为未来新版本的Javascript做好铺垫。
"严格模式"体现了Javascript更合理、更安全、更严谨的发展方向,包括IE 10在内的主流浏览器,都已经支持它,许多大项目已经开始全面拥抱它。

3.2、解构赋值(案例:lesson2-jiegou.js)

解构赋值的分类:数组解构赋值、对象解构赋值、字符串解构赋值、布尔值解构赋值、函数参数解构赋值、数值解构赋值
3.2.1、数组解构赋值
    // 块作用域:变量的重复声明,用块包起来就不会出现问题
    {}
    
    {
        let a, b, rest;
        [a, b] = [1, 2];
        // 输出1 2
        console.log(a, b);
    }
    
    {
        let a, b, rest;
        [a,b,...rest]=[1,2,3,4,5,6]
        // 输出1 2 [3,4,5,6]
        console.log(a,b,rest);
    }
3.2.1.1、默认值undefined
    // 没有配对成功,默认值为3;如果=3去掉,c是undefined
    {
        let a, b, c, rest;
        [a, b, c=3] = [1, 2];
        // 输出1 2 3
        console.log(a, b, c);
    }
3.2.1.2、使用场景
    // 变量交换
    {
        let a = 1;
        let b = 2;
        [a, b] = [b, a];
        // 输出2 1
        console.log(a, b)
    }
    
    // 取值方便
    {
        function f() {
            return [1,2]
        }
        let a, b;
        [a,b]=f();
        // 输出1 2
        console.log(a, b)
    }
        
    // 选择性接收变量
    {
        function f() {
            return [1,2,3,4,5]
        }
        let a,b,c;
        // 两个逗号,对应一个值
        [a,,,b]=f();
        // 输出1 4
        console.log(a, b)
    }
    
    {
        function f() {
            return [1,2,3,4,5]
        }
        let a,b,c;
        [a,...b]=f();
        // 输出1 [2,3,4,5]
        console.log(a, b)
    }
3.2.2、对象解构赋值
    // 左侧与右侧都是一个对象
    {
        let a,b;
        ({a, b} = {a:1,b:2});
        // 输出1 2
        console.log(a,b)
    }

    {
        let o={p:42,q:true};
        let {p,q}=o;
        // 输出:42 true
        console.log(p,q);
    }
3.2.2.1、默认值
    {
        let {a = 10, b = 5} = {a: 3};
        // 输出:3 5
        console.log(a, b);
    }
3.2.2.2、使用场景
    // 获取json
    {
        let metaData = {
            title: 'abc',
            test:[{
                title:'test',
                desc:'description'
            }]
        }
    
        let {title:esTitle,test:[{title:cnTitle}]} = metaData;
        // 输出:abc test
        console.log(esTitle, cnTitle)
    }

3.3、正则(案例:lesson3-regexp.js)略

新特性:构造函数的变化、正则方法的扩展、u修饰符、y修饰符、s修饰符
    {
        // es5
        let regex = new RegExp('xyz','i');
        let regex2 = new RegExp(/xyz/i);
    
        // 输出:true true
        console.log(regex.test('xyz123'), regex2.test('xyz123'));
    
        // es6
        // 允许第二个参数i覆盖修饰符ig
        let regex3 = new RegExp(/xyz/ig,'i');
        console.log(regex3.flags)
    }
    
    // y修饰符
    {
        let s = 'bbb_bb_b';
        // g跟y都是全局匹配;但是全局匹配不同点是,g是从上一次匹配继续开始查找(只要能找到,就算匹配成功)
        // y是从下一个匹配,如果第一个匹配不对,就算匹配失败
        // 第一步g跟y都可以匹配到bbb
        // 第二步只有g可以匹配到bb
        let a1 = /b+/g;
        let a2 = /b+/y;
    
        console.log('one',a1.exec(s),a2.exec(s));
        console.log('two',a1.exec(s),a2.exec(s));
    
        // 判断一个正则是否使用了y修饰符
        console.log(a1.sticky);
        console.log(a2.sticky);
    }
    
    // u修饰符(1、当处理字符串中的正则的长度大于2的时候 2、.是修饰小于2个字节)
    {
        // true: \uD83D\uDC2A当成了2个字母(字符)
        console.log('u-1',/^\uD83D/.test('\uD83D\uDC2A'));
        // false: \uD83D\uDC2A当成了1个字母(字符)
        console.log('u-2',/^\uD83D/u.test('\uD83D\uDC2A'));
    
        // 如果{}放的是unicode编码,要加个u,才能被识别
        // false
        console.log(/\u{61}/.test('a'));
        // true
        console.log(/\u{61}/u.test('a'));
    
        // 𠮷
        console.log(`\u{20BB7}`);
    
        let s = '𠮷';
        // false
        console.log('u',/^.$/.test(s))
        // true
        console.log('u',/^.$/u.test(s))
    
        // false
        console.log('test',/𠮷{2}/.test('𠮷𠮷'));
        // true
        console.log('test-2',/𠮷{2}/u.test('𠮷𠮷'));
    }

3.4、字符串(案例:lesson4-string.js)

新增特性:Unicode表示法、遍历接口、模板字符串、新增方法(10种)
npm install babel-polyfill --save-dev

label-polyfill.png

    {
        let str = 'string';
        // 查找是否包含了r
        console.log('查找是否包含了r:', str.includes('r'));        // true
        // 判断是否以str为起始
        console.log('判断是否以str为起始:',str.startsWith('str'));  // true
        // 判断是否以ng为结尾
        console.log('判断是否以ng为结尾:',str.endsWith('ng'));      // true
    }
    
    {
        let str = 'abc';
        // 字符串复制
        console.log('字符串复制:' + str.repeat(2));  // abcabc
    }
    
    
    {
        let name = 'list';
        let info = 'hello world';
        let m = `i am ${name},${info}`;
        console.log('字符串拼接:' + m)           // i am list,hello world
    }
    
    {
        // 通常运用在日期
    
        // 向前补:长度是4位,不够补0
        console.log('1'.padStart(4,'0'));       // 0001
    
        // 向后补
        console.log('1'.padEnd(2,'0'));         // 10
    }

3.5 数值扩展(案例:lesson5-number-math.js)

新增特性:新增方法、方法调用
    {
        // Number.isFinite()用来检查一个数值是否为有限的
        // 有进 true
        console.log('15',Number.isFinite(15));
        // 无进 false
        console.log('NaN',Number.isFinite(NaN));
        // 分母为0 false
        console.log('1/0',Number.isFinite('true'/0));
        // true
        console.log('NaN',Number.isNaN(NaN));
        // false
        console.log('0',Number.isNaN(0));
    }
    
    {
        // 判断一个数是不是整数
        // true
        console.log('判断25是不是整数:' + Number.isInteger(25));
        // true
        console.log('判断25.0数是不是整数:' + Number.isInteger(25.0));
        // false
        console.log('判断25.1数是不是整数:' + Number.isInteger(25.1));
        // false
        console.log('判断"25.1"数是不是整数:' + Number.isInteger('25.1'));
        // false
        console.log('判断"25"数是不是整数:' + Number.isInteger('25'));
    }
    
    
    {
        // 常量
        // 表示数的最大上线 9007199254740991
        console.log(Number.MAX_SAFE_INTEGER);
        // 表示数的最小下线 -9007199254740991
        console.log(Number.MIN_SAFE_INTEGER);
    
        // 10是一个安全的数 true
        console.log('10', Number.isSafeInteger(10));
        // false
        console.log('a', Number.isSafeInteger('a'));
    }
    
    {
        // Math.trunc取整数
        // 4
        console.log(4.1,Math.trunc(4.1));
        // 4
        console.log(4.9,Math.trunc(4.9));
    }
    
    {
        // 判断数字是正数还是负数
    
        // 负数为-1
        console.log('-5',Math.sign(-5));
        // 0为0
        console.log('0',Math.sign(0));
        // 正数为1
        console.log('5',Math.sign(5));
        // NaN
        console.log('foo',Math.sign('foo'));
    }
    
    {
        // -1的立方根
        console.log('-1的立方根:',Math.cbrt(-1))
        console.log('8的立方根:',Math.cbrt(8))
    }

3.6 数组扩展(案例:lesson6-array.js)

新增特性:Array.from、Array.of、copyWithin、find\findIndex、fill、entries\keys\values、inludes
    {
        // 是一个数组
        let arr = Array.of(3,4,7,9,11);
        console.log('arr是一个数组' + arr);      // 3,4,7,9,11
    
        // 空数组
        let empty = Array.of();
        console.log('空数组:',empty);            // 空数组: []
    }
    
    {
        let p = document.querySelectorAll('p');
        let pArr = Array.from(p);
        pArr.forEach(function (item) {
            // textContent原生js获取DOM节点内容
            // es6
            // hjy
            // oli
            console.log(item.textContent);
        });
    
        // 把数组的里参数都乘以2
        console.log(Array.from([1,3,5],function (item) {
            return item*2;  // 2,6,10
        }));
    }
    
    {
        // 数组里的参数都被替换成7
        console.log('fill-7',[1,'a',undefined].fill(7));    // [7, 7, 7]
        // 从起始位置1,不到3的位置,替换成7
        console.log('fill,post',['a','b','c'].fill(7,1,3)); // ["a", 7, 7]
    }
    
    {
        for(let index of ['1','c','ks'].keys()){
            // 0 1 2
            console.log('keys', index);
        }
    
        for(let value of ['1','c','ks'].values()){
            // 1 c ks
            console.log('values', value);
        }
    
        for(let [index,value] of ['1','c','ks'].entries()){
            // index=0, value=1
            // index=1, value=c
            // index=2, value=ks
            console.log('index=' + index + ', value=' + value);
        }
    }
    
    {
        // Array.prototype.copyWithin(target, start = 0, end = this.length)
        // target(必需):从该位置开始替换数据。如果为负值,表示倒数。
        // start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
        // end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
    
        // 从0的位置开始替换,从3开始读取,从4截止
        // 把4放到1的位置上:[4, 2, 3, 4, 5]
        console.log([1,2,3,4,5].copyWithin(0,3,4));
    }
    
    {
        console.log([1,2,3,4,5,6].find(function (item) {
            // 查找第一个符合大于3的值(找到了就停止)
            // 返回4
            return item > 3;
        }));
    
        console.log([1,2,3,4,5,6].findIndex(function (item) {
            // 查找第一个符合大于3的下标(找到了就停止)
            // 返回3
            return item > 3;
        }));
    }
    
    {
        // 数组中是不是包含了1
        // true
        console.log('number',[1,2,NaN].includes(1));
        // true
        console.log('number',[1,2,NaN].includes(NaN));
    }

3.7 函数扩展(案例:lesson7-function.js)

新增特性:参数默认值、rest参数、扩展运算符、箭头函数、this绑定、尾调用
    {
        function test(x,y = 'world') {
            // 如果y没有值,就采用默认值为world;如果有值,用采用传递过来的参数
            console.log('默认值',x,y)
        }
        test('hello');
        test('hello','hjy');
    
        // 错误写法:
        // function test(x,y = 'world',c)
    
        // 正确写法:
        // function test(x,y = 'world',c='bb')
    }
    
    {
        let x = 'test';
        // 都是取kill
        function test2(x,y=x) {
            console.log("作用域:",x,y);
        }
        // 作用域: kill kill
        test2('kill');
    
    
        function test3(c,y=x) {
            // 作用域: kill test
            console.log("作用域:",c,y);
        }
        test3('kill');
    }
    
    {
        // ...arg不确定传入几个参数,转成一个数组
        function test4(...arg) {
            for(let v of arg){
                // rest 1
                // rest 2
                // rest 3
                // rest 4
                // rest a
                console.log('rest',v);
            }
        }
        test4(1,2,3,4,'a');
    }
    
    {
        // 把数组转成一个离散的值
        console.log(...[1,2,4]);    // 1 2 4
        console.log('a',...[1,2,4]);// a 1 2 4
    }
    
    {
        // 函数
        // arrow函数名 v参数 v*2返回值
        let arrow = v => v*2;
        let arrow2 = () => 5;
    
        console.log('a',arrow(3));  // a 6
        console.log('a',arrow2());  // a 5
    }
    
    {
        // 尾调用(提升性能:函数地址嵌套)
        function tail(x) {
            console.log('tail',x);
        }
        function fx(x) {
            return tail(x)
        }
        fx(123)
    }

3.8 对象扩展(案例:lesson8-Obj.js)

新增特性:简洁表示法、属性表达式、扩展运算符、Object新增方法
    {
        // 简洁表达
        let o = 1;
        let k = 2;
        let es5 = {
            o:o,
            k:k
        };
    
        let es6 = {
            o,
            k
        };
        console.log(es5,es6);           // {o: 1, k: 2}  {o: 1, k: 2}
    
        // 对象里有方法
        let es5_method = {
            hello:function () {
                console.log('hello');
            }
        };
        let es6_method = {
            hello(){
                console.log('hello');
            }
        };
        console.log(es5_method.hello(),es6_method.hello());// hello hello
    }
    
    {
        // 属性表达式
        let a = 'b';
        let es5_obj = {
            a:'c'
        };
        // [a]是一个变量
        let es6_obj = {
            [a]:'c'
        };
        // {a: "c"}   {b: "c"}
        console.log(es5_obj,es6_obj)
    }
    
    {
        // 新增API
        // Object.is与三个等号相同  输出:true true
        console.log('判断2个字符串是否相等', Object.is('abc','abc'), 'abc' === 'abc');
    
        // 数组是引用类型,但是数组引用的是不同地址  输出:false false
        console.log('数组',Object.is([],[]), [] === []);
    
        // 当个对象合并成一个对象{a: "a", b: "b"}
        console.log('拷贝', Object.assign({a:'a'}, {b:'b'}));
    
        // 对数组进行遍历
        let test = {k:123,o:456};
        for(let [key,value] of Object.entries(test)){
            console.log(key,value);
        }
    }

3.9 symbol(案例:lesson9-symbol.js)

ES6新增加的类型
就是这种数据类型,提供一个独一无二(保证唯一)的值
    {
        // 声明
        let a1 = Symbol();
        let a2 = Symbol();
        // false
        console.log(a1 === a2);
    
        // 'a3'是一个key值
        let a3 = Symbol.for('a3');
        let a4 = Symbol.for('a3');
        // true
        console.log(a3 === a4);
    }
    
    {
        // 使用场景:两个相同的名字,不想去改变
        let a1 = Symbol.for('abc');
        let obj = {
            [a1]:'123',
            'abc':'345',
            'c':456
        };
        console.log(obj);       // {abc: "345", c: 456, Symbol(abc): "123"}
    
        // symbol的值取不到
        for(let [key,value] of Object.entries(obj)){
            // let of abc 345
            // let of c 456
            console.log('let of', key, value);
        }
    
        // 取到symbol的值
        Object.getOwnPropertySymbols(obj).forEach(function (item) {
            // 123
            console.log(obj[item])
        });
    
        // 两种参数的值都可以获取到
        Reflect.ownKeys(obj).forEach(function (item) {
            // ownKeys abc 345
            // ownKeys c 456
            // ownKeys Symbol(abc) 123
            console.log('ownKeys', item, obj[item]);
        })
    }

3.10 set-map数据结构(案例:lesson10-set-map.js)

    {
        let list = new Set();
        list.add(5);
        list.add(7);
        // 判断长度 输出:2
        console.log('size',list.size);
    }
    
    {
        let arr = [1,2,3,4,5];
        let list = new Set(arr);
        // 5
        console.log('size', list.size);
    }
    
    {
        // 运用场景:去重
        let list = new Set();
        list.add(1);
        list.add(2);
        // 重复元素,没有添加成功
        list.add(1);
        // {1, 2}
        console.log('list',list);
    
    
        let arr = [1,2,3,1,2];
        let list2 = new Set(arr);
        // 输出{1,2,3}
        console.log('unique',list2);
    }
    
    {
        let arr = ['add','delete','clear','has'];
        let list = new Set(arr);
    
        // 判断list里面有没有add这个值 输出:true
        console.log('has', list.has('add'));
        // 删除list
        console.log('delete', list.delete('add'), list);
        // 清空list
        list.clear();
        console.log('list',list);
    }
    
    {
        let arr = ['add','delete','clear','has'];
        let list = new Set(arr);
    
    
        for(let key of list.keys()){
            // keys add
            // keys delete
            // keys clear
            // keys has
            console.log('keys',key);
        }
        for(let value of list.values()){
            // values add
            // values delete
            // values clear
            // values has
            console.log('values',value);
        }
        for(let value of list){
            // values add
            // values delete
            // values clear
            // values has
            console.log('values',value);
        }
        for(let [key,value] of list.entries()){
            // entries add add
            // entries delete delete
            // entries clear clear
            // entries has has
            console.log('entries',key,value)
        }
    
        list.forEach(function (item) {
            // add
            // delete
            // clear
            // has
            console.log(item);
        })
    }
    
    
    {
        // 和set的数据类型不一样,WeakSet只是能对象,不能是数值,例如boolean
        // WeakSet对象这块,弱引用(不会检测对象在其他地方引用到,意味着不会跟垃圾回收机制挂钩到,简单说:WeakSet是一个地址的引用)
        // WeakSet没有clean、没有set、不能遍历
        let weakList = new WeakSet();
    
        let arg = {};
        weakList.add(arg);
        // 报错
        // weakList.add(2);
        console.log('weakList',weakList);
    }
    
    
    {
        let map = new Map();
        let arr = ['123'];
    
        map.set(arr,456);
        console.log('map', map, map.get(arr));      // key是123 value是456
    }
    
    {
        let map = new Map([['a',123],['b',456]]);
        console.log('map args', map);                   // {"a" => 123, "b" => 456}
        console.log('size', map.size);                  // 2
        console.log('delete', map.delete('a'), map);    // {"b" => 456}
        console.log('clear', map.clear(), map);         // {}
    }
    
    {
        // 与set和weakSet是一样的
        let weakmap = new WeakMap();
    }

3.11 map-set与数组和对象的比较(案例:lesson11-map-set-array-obj.js)

涉及的数据结构能使用map,不使用数组
数据的唯一性使用set
    {
        // map 和 array 数据结构横向对比:增删改查
        let map = new Map();
        let array = [];
        // 增
        map.set('t',1);
        array.push({t:1});
        console.info('map-array-add',map,array);
    
        // 查
        let map_exist = map.has('t');// true
        let array_exist = array.find(item=>item.t);// 遍历数组,查看是否存在;如果存在,就返回值
        console.info('map-array-find', map_exist, array_exist);
    
        // 改(map比较简单,array复杂)
        map.set('t',2);
        array.forEach(item => item.t ? item.t = 2 : '');
        console.info('map-array-modify',map, array);
    
        // 删(map比较简单,array复杂)
        map.delete('t');
        let index = array.findIndex(item => item.t);
        array.splice(index,1);
        console.info('map-array-remove',map, array);
    }
    
    
    {
        // set 和 array 的对比
        let set = new Set();
        let array = [];
    
        // 增
        set.add({t:1});
        array.push({t:1});
        console.info('set-array-add', set, array);
    
        // 查
        let set_exist = set.has({t:1});// false
        let array_exist = array.find(item=>item.t);// 遍历数组,查看是否存在;如果存在,就返回值
        console.info('set-array-find', set_exist, array_exist);
    
        // 改
        set.forEach(item => item.t ? item.t=2 :'');
        array.forEach(item => item.t ? item.t=2 :'');
        console.info('set-array-modify', set, array);
    
        // 删(set和array删除都相对麻烦)
        set.forEach(item => item.t ? set.delete(item) : '');
        let index = array.findIndex(item => item.t);
        array.splice(index, 1);
        console.info('set-array-remove', set, array);
    }
    
    {
        // set map 和 object 对比
        let item = {t:1};
        let map = new Map();
        let set = new Set();
        let obj = {};
    
        // 增
        map.set('t',1);
        set.add(item);
        obj['t'] = 1;
        console.info('map-set-obj', obj, map, set);
    
        // 查(obj不如map和set语义化)
        console.info({
            map_find:map.has('t'),
            set_find:set.has(item),
            obj_find:'t' in obj
        });
    
        // 改
        map.set('t',2);
        item.t = 2;
        obj['t'] = 2;
        console.log('map-set-obj-modify', obj, map, set);
    
        // 删(set和array删除都相对麻烦)
        map.delete('t');
        set.delete(item);
        delete obj['t'];
        console.log('map-set-obj-remove', obj, map, set);
    }

3.12 Proxy 和 Reflect(案例:lesson12-proxy-reflect.js)

Proxy代理,代理商:用户 和 商家(连接了用户和最真实对象的一个层)
Reflect反射
    {
        // 供应商 原始对象,存储真实数据
        let obj = {
            time:'2017-03-11',
            name:'net',
            _r:123
        };
    
        // 代理商
        let monitor = new Proxy(obj, {
            // 拦截(代理)对象属性的读取
            get(target, key){
                // target相当于obj
                // console.log(target);
    
                // 把2017替换成2018
                return target[key].replace('2017','2018');
            },
            // 拦截对象设置属性
            set(target, key, value){
                if(key === 'name'){
                    return target[key] = value
                }else {
                    return target[key];
                }
    
            },
            // 拦截key in object 操作
            has(target, key){
                if(key === 'name'){
                    return target[key]
                }else{
                    return false;
                }
            },
            // 拦截delete
            deleteProperty(target,key){
                if(key.indexOf('_') > -1){
                    delete target[key];
                    return true;
                }else{
                    return target[key];
                }
            },
            // 拦截Object.keys, Object.getOwnPropertySymbols, Object.getOwnPropertyNames
            // 保护time的key不被用户看到
            ownKeys(target){
                return Object.keys(target).filter(item=>item!='time')
            }
        });
    
        console.log('get', monitor.time);       // 2018-03-11
    
        monitor.time = '2019';
        monitor.name = 'hjy';
        console.log('set',monitor.time);        // 2018-03-11
        console.log('set',monitor.name);        // hjy
    
        // time被拦截了  true false
        console.log('has','name' in monitor, 'time' in monitor);
    
        // 对象依旧存在
        // delete monitor.time;
        // console.log('delete', monitor);
    
        // 成功的删掉_r
        // delete monitor._r;
        // console.log('delete', monitor);
    
        console.log('ownKeys',Object.keys(monitor));
    }
    
    {
        let obj = {
            time:'2017-03-11',
            name:'net',
            _r:123
        };
    
        // 读取time的值  
        console.log('Reflect get', Reflect.get(obj,'time'));    // 2017-03-11
        // 把name改成hjy
        Reflect.set(obj, 'name', 'hjy');                        
        console.log(obj);                                       // {time: "2017-03-11", name: "hjy", _r: 123}
        // 判断obj里是否有name
        console.log('has',Reflect.has(obj,'name'));             // true
    }
    
    {
        function validator(target, validator) {
            // 对target进行代理
            return new Proxy(target,{
                // 保存配置选项
                _validator:validator,
                // 对set进行修改
                set(traget,key,value,proxy){
                    if(target.hasOwnProperty(key)){
                        let va = this._validator[key];
                        if(!!va(value)){
                            return Reflect.set(target,key,value,proxy);
                        }else{
                            throw Error(`不能设置${key}到${value}`)
                        }
                    }else{
                        throw Error(`${key} 不存在`)
                    }
                }
            })
        }
    
        const personValidators={
            name(val){
                return typeof val === 'string'
            },
            age(val){
                return typeof val === 'number' && val > 18
            }
        };
    
        class Person{
            constructor(name,age){
                this.name = name;
                this.age = age;
                return validator(this,personValidators)
            }
        }
    
        const person = new Person('hjy',30);
        console.log(person);
    
        // 不能设置数字
        // person.name = 48;
        person.name = 'oli';
        console.log(person);
    
    }

3.13 类 和 对象(案例:lesson13-class.js)

类的概念:基本语法、类的继承、静态方法、静态属性、getter、setter
    {
        // 基本定义和生成实例
        class Parent{
            // 构造函数
            constructor(name='hjy'){
                this.name = name;
            }
        }
        let v_parent = new Parent('v');
        let v_parent2 = new Parent();
        // {name: "v"}
        console.log('构造函数和实例',v_parent);
        // {name: "hjy"}
        console.log('构造函数和实例',v_parent2);
    }
    
    {
        // 继承
        class Parent{
            // 构造函数
            constructor(name='hjy'){
                this.name = name;
            }
        }
    
        class Child extends Parent{
    
        }
        // {name: "hjy"}
        console.log('继承', new Child());
    }
    
    {
        // 继承传递参数
        class Parent{
            // 构造函数
            constructor(name='hjy'){
                this.name = name;
            }
        }
    
        class Child extends Parent{
            constructor(name='child'){
                // 修改父类的参数(要把super放在第一行)
                super(name);
    
                // 子类增加自己的属性
                this.type='childType';
            }
        }
        // {name: "lio", type: "childType"}
        console.log('子类向父类传递参数', new Child('lio'));
    }
    
    {
        // getter setter
        class Parent{
            // 构造函数
            constructor(name='hjy'){
                this.name = name;
            }
    
            get longName(){
                return '姓名:' + this.name
            }
    
            set longName(value){
                this.name = value;
            }
        }
    
        let v = new Parent();
        // hjy
        console.log('getter',v.longName);
        v.longName='lio';
        // lio
        console.log('setter',v.longName);
    }
    
    {
        // 静态方法(通过类调用,而不是通过类的实例去调用)
        class Parent{
            // 构造函数
            constructor(name='hjy'){
                this.name = name;
            }
    
            // 静态方法
            static tell(){
                console.log('tell');
            }
        }
        // tell
        Parent.tell();
    }
    
    {
        // 静态属性
        class Parent{
            // 构造函数
            constructor(name='hjy'){
                this.name = name;
            }
    
            // 静态方法(不能定义静态属性)
            static tell(){
                console.log('tell');
            }
        }
        // 静态属性
        Parent.type = 'test';
        // tell
        console.log('静态属性',Parent.type);
    }

3.14 Promise(案例:lesson14-promise.js)

异步编程的解决方法
A执行完再执行B,两种实现方式:回调、事件触发
    {
        // es5回调解决异步操作
        let ajax = function (callback) {
            console.log('执行');
            setTimeout(function () {
                // 判断回调是不是存在,如果存在,执行下一步
                callback && callback.call()
            },1000)
        };
        ajax(function () {
            console.log('timeout1');
        });
    }
    
    {
        // es6
        let ajax = function () {
            console.log('执行2');
            // 返回一个Promise实例(执行下一步功能)
            // resolve执行下一步操作
            // reject中断下一步操作
            return new Promise(function (resolve,reject) {
                setTimeout(function () {
                    resolve();
                },1000);
            })
        };
    
        ajax().then(function () {
            console.log('promise','timeout2');
        })
    }
    
    {
        // A执行完再执行B,B执行完了执行C ...
        let ajax = function () {
            console.log('执行3');
            // 返回一个Promise实例(执行下一步功能)
            // resolve执行下一步操作
            // reject中断下一步操作
            return new Promise(function (resolve,reject) {
                setTimeout(function () {
                    resolve();
                },1000);
            })
        };
    
        ajax().then(function () {
            return new Promise(function (resolve,reject) {
                // 又可以下一步
                resolve();
            },2000)
        }).then(function () {
            console.log('timeout3');
        })
    }
    
    {
        // catch捕获错误
        let ajax = function (num) {
            console.log('执行4');
            return new Promise(function (resolve,reject) {
                // 如果大于5,执行下一步
                if(num > 5){
                    resolve();
                }else{
                    // 抛出错误
                    throw new Error('出错了');
                }
            })
        };
    
        ajax(6).then(function () {
            console.log('log',6);
        }).catch(function (err) {
            console.log('catch',err);
        });
    
        ajax(3).then(function () {
            console.log('log',3);
        }).catch(function (err) {
            console.log('catch',err);
        })
    }
    
    {
        // 所有图片加载完再添加到页面
        function loadImg(src) {
            return new Promise((resolve,reject) => {
                let img = document.createElement('img');
                img.src = src;
                // 图片加载完
                img.onload=function () {
                    resolve(img);
                };
                // 图片加载失败
                img.onerror = function (err) {
                    reject(err);
                };
            })
        }
    
        function showImgs(imgs) {
            imgs.forEach(function (img) {
                document.body.appendChild(img);
            })
        }
    
        // all:把多个Promise实例当成一个Promise实例
        Promise.all([
            // 三张图片都加载完,才会触发all,才执行then
            loadImg('http://myoli.xin/public/images/banner.jpg'),
            loadImg('http://myoli.xin/public/images/banner.jpg'),
            loadImg('http://myoli.xin/public/images/banner.jpg')
        ]).then(showImgs)
    }
    
    {
        // 有一个图片加载完成添加到页面
        function loadImg(src) {
            return new Promise((resolve,reject) => {
                let img = document.createElement('img');
                img.src = src;
                // 图片加载完
                img.onload=function () {
                    resolve(img);
                };
                // 图片加载失败
                img.onerror = function (err) {
                    reject(err);
                };
            })
        }
    
        function showImgs(img) {
            let p = document.createElement('p');
            p.appendChild(img);
            document.body.appendChild(p)
        }
    
        // 三张图片,只要有一个图片加载出来,那个就先显示在页面上
        Promise.race([
            loadImg('http://myoli.xin/public/images/banner.jpg'),
            loadImg('http://myoli.xin/public/images/banner.jpg'),
            loadImg('http://myoli.xin/public/images/banner.jpg')
        ]).then(showImgs)
    }

3.15 Iterator(案例:lesson15-iterator.js)

操作数组、object、map、set
    {
        let arr = ['hello','world'];
        let map = arr[Symbol.iterator]();
        // {value: "hello", done: false}
        console.log(map.next());
        // {value: "world", done: false}
        console.log(map.next());
        // {value: undefined, done: true}  true代表没有下一步
        console.log(map.next());
    }
    
    {
        // 自定义iterator接口
        // obj数据是我们自己填充
        let obj = {
            start:[1,3,2],
            end:[7,9,8],
            // Symbol.iterator变量名
            [Symbol.iterator](){
                let self = this;
                // 记录当前遍历索引
                let index = 0;
                // start和end合并成一个数组
                let arr = self.start.concat(self.end);
                // 记录数组的长度
                let len = arr.length;
                return {
                    next(){
                        if(index < len){
                            return {
                                value:arr[index++],
                                done:false
                            }
                        } else {
                            return {
                                value:arr[index++],
                                done:true
                            }
                        }
                    }
                }
            }
        }
    
        for(let key of obj){
            console.log(key);
        }
    }
    
    
    {
        // 对数组进行遍历
        let arr = ['hello','world'];
        for(let value of arr){
            // hello
            // world
            console.log('value',value);
        }
    }

3.16 Generator(案例:lesson16-decorators.js)

异步编程的一种解决方案
    {
        // genertaor基本定义
        // 与普通的函数不同:* 、 yield
        let tell = function* () {
            yield 'a';
            yield 'b';
            return 'c';
        };
    
        // 调用tell,执行到第一个yield停止下来
        let k = tell();
    
        // 执行第一个yield
        // {value: "a", done: false}
        console.log(k.next());
    
        // 执行第二个yield
        // {value: "b", done: false}
        console.log(k.next());
    
        // 执行retrun
        // {value: "c", done: true}
        console.log(k.next());
    
        // {value: undefined, done: true}
        console.log(k.next());
    }
    
    {
        // of遍历
        let obj = {
    
        };
        obj[Symbol.iterator] = function* () {
            yield 1;
            yield 2;
            yield 3;
        };
    
        for(let value of obj){
            // 1
            // 2
            // 3
            console.log('value',value);
        }
    }
    
    {
        let state = function* () {
            while(1){
                yield 'A';
                yield 'b';
                yield 'c';
            }
        }
        let status = state();
        // {value: "A", done: false}
        // {value: "b", done: false}
        // {value: "c", done: false}
        // {value: "A", done: false}
        // {value: "b", done: false}
        console.log(status.next());
        console.log(status.next());
        console.log(status.next());
        console.log(status.next());
        console.log(status.next());
    }
    
    {
        // 抽奖
        let draw = function (count) {
            // 具体抽奖逻辑
            console.info(`剩余${count}次`);
        };
    
        let residue = function* (count) {
            while (count > 0){
                count--;
                yield draw(count);
            }
        };
    
        // 可以抽奖5次,如果是最后一次,点击无效
        let star = residue(5);
        let btn = document.createElement('button');
        btn.id = 'start';
        btn.textContent = '抽奖';
        document.body.appendChild(btn);
        document.getElementById('start').addEventListener('click',function () {
            star.next();
        },false)
    }
    
    {
        // 长轮询(接口请求失败,一直请求)
        let ajax = function* () {
            yield new Promise(function (resolve,reject) {
                // 接口
                setTimeout(function () {
                    resolve({code:0})
                },200);
            })
    
        };
    
        let pull = function () {
            let genertaor = ajax();
            let step = genertaor.next();
            step.value.then(function (d) {
                if(d.code != 0){
                    setTimeout(function () {
                        console.log('wait');
                        pull();
                    },1000);
                }else{
                    console.log(d);
                }
            })
        };
    
        pull();
    }

3.17 Decorator(案例:lesson17-decorators.js)

修饰器:是一个函数,修改类的行为(扩展类的动能,只在类里修改有用)
    {
        // 是一个函数
        let readonly = function (target, name, descriptor) {
            descriptor.writable = false;
            return descriptor
        };
    
        // 修改类的行为
        class Test{
            // 加了修饰器,就是不能重新修改参数;只有只读的状态
            // @readonly与上面的readonly要一致
            @readonly
            time(){
                return '2017-03-11'
            }
        }
    
        let test = new Test();
        // 加了修饰器,就是不能重新修改参数;只有只读的状态
        // 报错
        // test.time = function () {
        //     console.log('reset name')
        // }
        // 2017-03-11
        console.log(test.time())
    }
    
    
    {
        let typename = function (target,name,descriptor) {
            // 静态属性
            target.myname = 'hello';
        };
    
        // 修饰器(对类进行修饰)
        @typename
        class Test{
    
        }
        console.log('类修饰符',Test.myname);    // hello
        // 第三方库修饰器的js库:core-decorators; npm install core-decorators
    }
    
    {
        // 看广告是show还是click
        let log = (type) => {
            return function (target,name,descriptor) {
                let src_method = descriptor.value;
                // 方法重新赋值
                descriptor.value=(...arg)=>{
                    src_method.apply(target,arg);
                    console.info(`log ${type}`);
                }
            }
        }
    
        class AD{
            @log('show')
            show(){
                console.info('ad is show');
            }
    
            @log('click')
            click(){
                console.info('ad is click');
            }
    
        }
    
        // 实例化
        let ad = new AD();
        ad.show();
        ad.click();
    }

3.18 模块化(案例:lesson18-module.js)

    let A = 123;
    let test = function () {
        console.log('test');
    }
    class Hello{
        test(){
            console.log('class');
        }
    }
    export default {
        A,
        test,
        Hello
    }
    
    // 模块化:导入所有 lesson只是一个别名
    import * as lesson from './class/lesson18-module';
    console.log(lesson.A);
    console.log(lesson.test);
    
    import Lesson18 from './class/lesson18-module';
    console.log(Lesson18.A);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值