美文网首页
2018W23 学习笔记

2018W23 学习笔记

作者: 唐小无 | 来源:发表于2018-06-10 20:11 被阅读0次

    这周因为朋友结婚帮忙的缘故,学习的内容明显下降了不少。所以,等明天开始,得需要恢复之前每天学习的强度。

    本周的学习共分为3块:

    1. ES6基础学习与深入;
    2. Vue源码阅读;
    3. 前端进阶班的预习;
      下面我们按照上面模块一起去看一下本周我到底获得了哪些收货。

    1.ES6学习

    阅读完成《深入理解ES6》的第三章。第三章主要讲述的是函数的ES6新特性。
    我们都知道ES6是ES5的加强与补充,是为了解决ES5中某些遗留问题而提出的新的解决方案或者加强,所以顺着这个思路,我就去做了这样的笔记。

    1.1 ES6函数新特性

    在ES6中,针对函数,补充了如下的一些特性:

    • 参数默认值
    • 使用不具名函数
    • 函数构造器增强
    • 扩展运算符
    • 函数的双重用途
    • 块级函数
    • 箭头函数
    • 尾调用优化
    1.1.1 参数默认值

    传统的ES5设置函数默认值需要逐个对参数进行设置,所以代码量非常多,而且对于JS这种不限制函数参数的行为其扩展性也很差。所以ES6在ES5的基础上增加了参数默认值的特效,其语法如下:

        function demo(url, timeout = 2000 , fn = function()
            {console.log('do it')
        })
    

    值得注意的是,我们可以向参数传递Undefined值来使用默认的参数值,以上面函数为例,

          demo('http://www.baidu.com',undefined,fn)
    

    这样就可以继续使用第二个参数的默认值了。

    初次之外,还涉及到了2个比较“冷门的问题”:

    1. ES6参数默认值是如何影响argument对象;
    2. 参数默认值的暂时性死区;

    1.1.2 使用不具名函数

    ES5的不具名的arguments对象在实际使用过程中会有很多的限制。在书中,就通过underscorejs库中Pick函数的讲解来说出arguments的不足。

      // 复制特定对象的特定属性
      function pick(object) {
        let result = Object.create(null);
        // 从第二个参数开始处理
        for (let i = 1, len = arguments.length; i < len; i++) {
          result[arguments[i]] = object[arguments[i]];
      }
        return result;
      }
    
    
    1. 虽然该函数能处理多个函数,但是在函数的表现上则完全看不出;
    2. 函数的第一个参数是选中的目标对象,从第二个开始才是需要复制的属性。

    因此ES6引入了剩余参数这个概念,使用剩余函数对上述函数进行改写,则清晰和优雅不少。

      function pick(object, ...keys) {
        let result = Object.create(null);
        for (let i = 0, len = keys.length; i < len; i++) {
        result[keys[i]] = object[keys[i]];
        }
        return result;
    }
    

    通过引入剩余参数,我们就可以知道函数可以处理多余的函数。并且这与包含所有参数的arguements不同,我们可以单独对剩余函数进行处理。当然剩余函数也有剩余的不足,主要有以下两点:

    1. 剩余参数必须要放在最后面;
    2. 剩余参数放在setter函数中不可用,会报语法错误。

    1.1.3 函数构造器

    作者声称,函数默认值加上剩余函数加强了函数构造器的能力,但是,在实际工作中,笔者觉得函数构造器的用处并不多。


    1.2.4 扩展运算符

    剩余参数是将多个参数添加进数组,而扩展运算符则是将数组的元素分成单个的元素,类似于split的功能。它主要的目的是代替apply。其使用场景如下:

       let values = [1,8,3];
      // ES5版本
      Math.max.apply(Math, values);
    
       // ES6版本
      Math.max(...values);
    

    在之前的ES5版本中,要实现求一个数组的最大数,需要使用apply去更改上下文的执行环境,而有了扩展运算符之后,则轻松很多,并且从语义化角度上来说,也清晰不少。


    1.1.4 函数的双重用途

    在ES5中,函数是否调用new操作符则意味着不同的用途。没有new操作符,它就是执行函数体内的代码。而有了new,函数就会执行内部[[ constructor]]方法,构建一个对象。所以这就是函数的双重用途的意思。
    在ES5中,判断函数是否调用了new操作,最简单也是最流行的一种做法就是使用instanceof这个方法,但是,这个方法也有明显的缺陷,开发者可以使用apply去改变函数执行的上下文顺序,从而使instanceof的执行判断出错。

    function Person(name) {
        if (this instanceof Person) {
            this.name = name; // 使用 new
          } else {
              throw new Error("You must use new with Person.")
          }
         }  
          var person = new Person("Nicholas");
          var notAPerson = Person.call(person, "Michael"); // 奏效了!
    

    因此在ES6中引入了new.target来弥补相关不足。

        function Person(name){
            if(typeof new.target != undefined){
                this.name =name;
            }else{
                throw new Error('must with new');
            }
        }
    
    

    其底层原理是,在调用new 操作符时,调用[[ constructor ]]方法,new.target才会生成,(否则为undefined)并且将this对象赋值为原构造函数。


    1.1.5 ES6箭头函数

    之前也学习过ES6箭头函数,但是没有想到的是,ES6函数为了增强ES5函数的一些不足,竟然和传统的函数有很多不一样的特点:

    1. 没有this,super,arguments和new.target绑定;
    2. 箭头函数不能作为构造函数,也就是说不能被new,也没有prototype属性;
    3. 不能更改this的指向(js深恶痛绝的this指向问题);
    4. 不能重复相同的参数命名。

    这些特点是为了减少箭头函数内部的错误与不确定性,为了js函数更好的运行。


    2. Vue源码学习

    主要是看了第500-900行的代码,粗略地知道了Vue对数组的监听。

    首先获取数组的原型对象,在这个对象上有数组的方法。

        var arrProto = Array.prototype;
    

    然后使用Object.create的方法创建了一个空对象,其中它的原型链上有数组方法的集合。

        var arrMethods = Object.create(arrProto);
    

    创建一个数组方法的集合:

        var methodsToPatch = [
                'push',
                'pop',
                'shift',
                'unshift',
                'splice',
                'sort',
                'reverse'
            ];
    
    

    最关键的一步:对arrMethods进行构建:

    给arrMethods添加属性

    1. 遍历methodsToPatch,在回调函数中调用def函数给arrMethods添加方法相对应的属性
        methodsToPatch.forEach(method => {
                def(arrMethods, method, function mutator() {
                    // 相关代码第二步进行解析
                })
            });
    
        function def(obj, key, val, enumerable) {
                Object.defineProperty(obj, key, {
                    value: val,
                    enumerable: !!enumerable,
                    writable: true,
                    configurable: true
                });
            }Ï
    
    
    1. muator函数的定义
           function mutator() {
                //定义args容器,并且获取函数参数的长度
                var args = [],
                    len = arguments.length;
    
                while (len--) args[len] = arguments[len]; //将类数组转换成数组
    
                //这里的this指的就是arrMethods 调用arrMethods中的方法和参数
                var result = original.apply(this, args);
    
                //监听类 下面代码就调用了它的notify和observeArray方法
                var ob = this.__ob__; 
                var inserted;
    
                //如果是push/unshift/splice方法 对inserted进行赋值
                switch (method) {
                    case 'push':
                    case 'unshift':
                        inserted = args;
                        break;
    
                    case 'splice':
                        inserted = args.splice(2);
                        break;
                }
    
                
                if (inserted) {
                    ob.observeArray(inserted); //对传入的参数进行监听
                }
    
                ob.deep.notify(); //通知视图发生变化
    
                return result;
    
            };  
        
    

    3.课程进阶学习

    这里总结性的语言就不写了,抛出问题,测试一下是否能回答出:

    • 有哪3种为DOM元素注册事件处理函数的方式?分别有什么限制和优点?

    • Dom Event接口中哪些属性和接口需要了解?

    • 如何自定义一个Event事件?请写出一个demo;

    • JS事件的传播是如何传播的?

    • 简述下面代码的执行顺序

            // html 
            <div id='outter'>
                <p id='inner'> click </p>
            </div>
    
            // js
            
            let outter = document.getElementById('outter');
            let inner = document.getElementById('inner');
            
            outter.addEventListener('click', function () {
                console.log('outter-true')
            }, true);
            inner.addEventListener('click', function () {
                console.log('inner-true')
            }, true);
            inner.addEventListener('click', function () {
                console.log('inner-false')
            }, false);
            outter.addEventListener('click', function () {
                console.log('outter-false')
            }, false);
    
    
    • 请解释一下什么是JS事件代理?

    • 请简单地写一下事件代理的demo;

    • 可以使用哪个事件来阻止事件的传播?

    • util.callbackify这个API的作用是什么?

    • 回调函数中的第一个参数和第二个参数分别是什么?

    • 请写出API的具体使用方法:将一个异步函数转换为错误回调优先的函数

    • 回调函数中的 null 有什么意义么?

    • 回调函数中的错误原因可以通过什么属性获取?

    • generator对象是什么?怎样才能获取到?

    • 请写出generator最基本的语法;

    • 调用一个生成器函数会立即执行函数体里面的语句么?

    • 发布/订阅模式和观察者的区别是什么?


    梳理完本周学习的内容,发现有很多都已经忘了,不多说了,需要赶紧去复习。

    相关文章

      网友评论

          本文标题:2018W23 学习笔记

          本文链接:https://www.haomeiwen.com/subject/uilqeftx.html