《ES6标准入门》学习笔记

        //1,声明关键字:const、let
            const plus1 = a => a + 1;
            const mult2 = b => b * 2;
            console.log(mult2(plus1(1)));

            //plus1 = 2;//const声明的变量的值不能重新被赋值
                        //let声明一个块级作用域,只在其所在包含块中有效。
        //2 箭头函数=>

        //箭头函数
        /*
        1.参数 => 返回值
        2.this绑定(其内部并没有this,因此也不能作为构造函数和new构造器组合使用)
        3.等同于匿名函数
        4. 不能使用call、apply、bind方法
         */
        console.log([1,2,3].map(x => x +1));//[2,3,4]

        //箭头函数绑定this
        let handler = {
            id: '123456',
            init:function () {

                //因为箭头函数中没有this,所以下行代码中的this为init方法的this,指向handler
                document.addEventListener('click', event => this.doSomething(event.type), false);
            },
            doSomething: function (type) {
                console.log("Handling " + type + " for " + this.id);
            }
        };
        handler.init();

        //箭头函数练习
        function foo() {
            return () => {
                return () => {
                    return () => {
                        console.log("id:", this.id);
                    }
                }
            }
        }
        foo.call({id: "zgatry"})()()();//输出zgatry,这里通过.call把foo函数内部的this指向了{id:"zgatry"}对象

        //箭头函数也不像其他函数一样自带类数组arguments
        function fn() {
            setTimeout(() => {

                //这里的arguments其实是fn函数的arguments
                console.log("args:", arguments);
            }, 1000);
        }
        fn("zgatry", 2, 3, 4);//输出"zgatry", 2, 3, 4

        //箭头函数总结:主要用于解决this绑定、简化函数提升可读性问题。<<----个人理解

        //关于this绑定的问题,ES7提出了“::”this绑定符。它会将符号左边的对象作为右边代码的this指向。该符号返回的是原对象,可以进行链式写法。


        //尾调用优化:在一个函数的最后一步调用另一个函数
        //函数调用——在内存形成调用记录(调用帧)——嵌套调用时,外部函数必须等内部的函数执行完毕,它的调用帧才会消失。它们的组合形成“调用栈”。
        //所以调用帧最好是及时清除,否则对内存是极大的消耗。
        //尾调用优点:及时清除外部函数的调用帧,减少调用帧的个数。

        //注意:尾调用优化在严格模式才会生效
        //例如:
        function plusThenMult(a, b) {
            var val = a + b;
            console.log("加的结果", val);
            return mult(a, b);
        }
        function mult(a, b) {
            var val = a * b;
            console.log("乘的结果", val);
        }
        plusThenMult(1,2);

        //尾调用不一定出现在尾部,只要求是最后一步。

        //尾调用拓展——尾递归, 还涉及到复杂度
        //阶乘函数的例子

        //尾递归的方式
        function factorial(n, total) {
            if(n === 1) return total;
            return factorial(n - 1, n * total);
            //只有一个调用帧,复杂度O(1);
        }
        //正常的方式
        function factor2(n) {
            if(n === 1) return 1;
            return n * factor2( n - 1);
            //形成多层调用帧,容易发生栈溢出错误stack overflow
            //形成n层调用帧,复杂度O(n);
        }

        //尾调用优化对递归操作意义大

        //上面使用尾调用优化的阶乘函数传参怪怪的,我要得到5的阶乘,还要这样传 (5, 1);
        //使用ES6的函数默认值就优雅多了
        
        //改写
        function factorial(n, total = 1) {  //默认值只有在total为undefined时才生效
            if(n === 1) return total;
            return factorial(n - 1, n * total);
            //只有一个调用帧,复杂度O(1);
        }
        console.log("5的阶乘:",factorial(5));//输出120

        //Symbol
        /*
        新的原始数据类型——独一无二——由Symbol函数生成——类似于字符串
        */
        let s = Symbol();
        console.log(typeof s);
        let s1 = Symbol('foo'); //Symbol传参用以与其他值区分,解释该值。

        let s2 = Symbol('bar');
        s1.toString();
        s2.toString();
        console.log(s1);
        console.log(s2);
        
        //主要用于对象的属性名的标示符,避免属性名重复导致属性被覆盖的问题
        //增强的对象写法
        let s3 = Symbol('test'); 
        let obj = {
            [s](args) {
                console.log(1);
            },
            name: 'zgatry'
        }
        console.log(obj[s]);

        //ES6的class类————ES5的构造函数的一层包装

        class userMethod {
            constructor (ele) {
                this.$class = ele;
            }
            renderHtml () {
                console.log('渲染用户页面');
                return true;
            }
        }

        let userInfo = new userMethod('zgatry');
        userInfo.renderHtml();
        console.log(userInfo.$class);

        //所有的实例共享一个原型对象
        let user1 = new userMethod('aoao');
        let user2 = new userMethod('aobo');

        console.log("相同的原型对象?", user1.__proto__ === user2.__proto__);

        //实例为原型添加方法<<---不推荐使用
        user1.__proto__.plus = function (val){
            return val + 1
        }
        console.log("原型方法添加成功", user2.plus(2));
        
        //不存在变量提升:ES不会把变量声明提升到代码头部      let命令也是不提升的
        // new Foo();//Foo is not defined
        // class Foo{}
        //上面的特性与继承有关:为了保证子类在父类之后定义。
        {
            let Foo = class {};
            class Bar extends Foo {     //通过extend关键字进行继承

            }
        }
        //关于继承
        //继续使用上面的userMethod的类
        class VIPuser extends userMethod {
            constructor($class, VIPnumber) {
                super($class);  //调用父类的constructor(x, y);   不调用该方法会报错   不加$class则继承不到父类的属性但this可以用了
                this.VIPnumber = VIPnumber; //子类没有this,需要通过super关键字,它指代了父类的实例(即父类的this对象)
            }
        }

        let VIP1 = new VIPuser('bobo', 1);
        console.log(VIP1.$class, VIP1.renderHtml(), VIP1.VIPnumber);
        

        //两条继承链的解释和说明
        //例子
        class A {}
        class B extends A {}
        //1.作为对象,B的原型(__proto__)就是父类A;
        B.prototype.__proto__ = A.prototype;
        //2.作为构造函数, 子类B的原型(prototype属性)是父类的实例.
        B.prototype = new A();

        //class的存值函数和取值函数,为某个属性添加取值和存值, 捕获取值和存值行为
        class MyClass {
            constructor() {
                //...
            }
            get prop() {
                console.log('getter');
            }
            set prop(value) {
                console.log('setter:', value);
            }
        }
        var inst = new MyClass();
        inst.prop = 123;
        inst.prop;

        //ES6在类和模块的内部默认使用严格模式
        
        //Generator方法   在方法前加*表示    暂不拓展

        //静态方法与静态属性     在方法前加static表示
        /*
            1.静态方法不会被实例继承
            2.静态方法可以被子类继承
            3.只能直接通过类调用。
            4.但也可以通过super对象调用(因为super是父类的this)
        */
        class Foo {
            static classMethod () {
                return 'hello'
            }
        }
        class Bar extends Foo {
            static classMethod () {
                return super.classMethod() + ', too';
            }
        }
        console.log(Bar.classMethod());
        
        //静态属性
        //两种无效的写法
        // class Foo {
        //     //写法一
        //     prop:2

        //     //写法二
        //     static prop:2
        // }

        //实例属性的新写法  ES7
        // class Myclass {
        //     myProp = 42;
        //     constructor () {
        //         console.log(this.myProp);//42
                
        //     }
        // }
        // class Myclass {
        //     static myStaticProp = 42;
        //     constructor () {
        //         console.log(Myclass.myProp);//42
                
        //     }
        // }

        /*
        模块
        Module语法是JavaScript的标准语法
        1.使用import替代require
        2.使用export替代module.exports

        //bad
        const moduleA = require('moduleA');
        const func1 = moduleA.func1;
        const func2 = moduleA.func2;

        //good 
        import {func1, func2} form 'moduleA';

        //CommonJs 写法
        var React = require('react');
        var Breadcrumbs = React.createClass({
			render () {
				return <nav />;
			}
        });
        module.exports = Breadcrumbs;

        //ES6写法
        import React from 'react';
        const Breadcrumbs = React.createClass({
			render () {
				return <nav />;
			}
        });
        export default Breadcrumbs;	//只有一个输出值的时候使用default,多个值就不适用。
        */

        /*

		异步操作和async函数

		ES6前异步编程的方法
		1.回调函数
		2.事件监听
		3.发布-订阅
		4.promise对象

		回调函数
		-->>回调函数噩梦:多个回调函数嵌套的问题上,比如说依次读取多个文件,就会出现多重嵌套,代码很快就会乱做一团。
		fs.readFile(fileA, function(err, data) {
			fs.readFile(fileB, function(err, data) {
				//...
			})
		})
		
		Promise
		Promise允许将回调函数的横向加载改成纵向加载。
		Promise 提供了then方法用于执行回调函数,catch方法捕捉执行过程中跑出的错误。
		缺点:代码冗余,缺乏语义化。
		var readFile = require('fs-readfile-promise');

		readFile(fileA)
		.then(function(data) {
			console.log(data.toString());
		})
		.then(function() {
			return readFile(fileB);
		})
		.then(function(data) {
			console.log(data.toString);
		})
		.catch(function(err) {
			console.log(err);
		});

        基于Promise对象的自动执行器
        var fs = require('fs');

        var readfile = function(fileName) {
            return new Promise(function (resolve, reject) {
                fs.readFile(fileName, function(error, data) {
                    if(error) reject(error);
                    resolve(data);
                });
            });
        };
        var gen = function* () {
            var f1 = yield readFile('/etc/fstab');
            var f2 = yield readFile('/etc/shells');
            console.log(f1.toString());
            console.log(f2.toString());
        };

        //手动执行Generator函数
        var g = gen();

        g.next().value.then(function(data) {
            g.next().value.then(function(data) {
                g.next(data);
            });
        });

        //手动操作其实就是通过then层层执行回调函数。

        //现在来写自动执行器

        var run = function(gen) {
            var g = gen();
            function next() {
                var result = g.next(data);
                if(result.done) return result.value;
                result.value.then(function(data) {
                    next(data);
                });
            }
            next();
        };

        //这样Generator函数就可以自动执行了。
        run(gen);

        async函数———Generator函数的语法糖

        用async实现读取两个文件的范例:
        
        var asyncReadFile = async function() {
            var f1 = await readFile('/etc/fatab');
            var f2 = await readFile('/etc/shells');
            console.log(f1.toString());
            console.log(f2.toString());
        };
    
        var result = asyncReadFile();

        

        */

editTime: 2016/10/09

posted @ 2017-02-08 14:30  君寻不惑  阅读(351)  评论(0编辑  收藏  举报