zhuhuiwen Front-end Dev Engineer

js原生框架第二天

2016-12-12

12/13/2016 3:29:39 PM

将之前的笔记1212号的干掉了,尽进行根据代码进行总结

jQ原型上的核心成员

  1. jquery 属性,获取jQ的版本
  2. length 属性,实例的length属性默认值
  3. get方法,传参按照指定下标获取对应的DOM元素,不传参把jQ对象转换为数组返回

  4. eq 方法
  5. first 方法
  6. last 方法
  7. push
  8. sort
  9. splice
  10. toArray
  11. slice
  12. pushStack
  13. end
  14. each
  15. map

jquery 属性

  1. 作用
    1. 获取jq的版本
  2. 代码
    1. console.log($().jquery);//3.1.0

$().length

  1. 作用
    1. 0 是在原型length:0
    2. 是为了保持完整性
  2. 执行代码

    console.log($().length);//0

get方法

  1. 作用
    1. 不传参把jQ对象转换为数组返回
    2. 传参按照指定下标获取对应的DOM元素,
  2. 实现
    1. jq中的实现

       /*
       * get方法
       * 不传参把jQ对象转换为数组返回
       * 传参按照指定下标获取对应的DOM元素,
       * */
       console.log($('li').get());
       console.log($('li').get(0));
       console.log($('li').get(5));
       console.log($('li').get(-1));//获取最后一个
       console.log($('li').get(1,2));//只会接收一个参数,第二个参数会被忽略
      
  3. 进行框架封装的
    1. 思路
      1. 不传参数,借用slice方法把实例对象转换为数组返回
      2. 传参数,进行根据下标值来返回一个dom对象
    2. 代码

       get : function(i){
           /*
           * 思路:
           *   1. 不传参数,借用slice方法把实例对象转换为数组返回
           *   2. 传参数,进行根据下标值来返回一个dom对象
           * */
           if(arguments.length==0){
               return [].slice.call(this);
           }else{
               /*
               * 根据参数的下标
               * 1. 如果下标大于0,直接进行  因为是伪数组对象[下标值]
               * 2. 如果是小于0,直接进行从长度+i
               * */
               if(i>=0){
                   return this[i];
               }else{
                   return this[this.length+i]
               }
           }
       },
       _get : function(i){
           if(arguments.length==0){
               return [].slice.call(this);
           }else{
               return i>=0?this[i]:this[this.length+i];
           }
       }
      

eq方法

  1. 作用
    1. eq返回的是jq对象
      1. 没有参数,直接进行返回一个空对象
      2. 有参数,进行返回获得的jq对象
  2. jq中eq的返回结果

     /*
     * eq返回的是jq对象
     * 1. 没有参数,直接进行返回一个空对象
     * 2. 有参数,进行返回获得的jq对象
     * */
     console.log($('li').eq());//jQuery.fn.init[0]
     console.log($('li').eq(0));//jQuery.fn.init[1]
     console.log($('li').eq(9));//jQuery.fn.init[0]
     console.log($('li').eq(undefined));//jQuery.fn.init[0]
    
  3. 封装eq和first和last
    1. 实现eq方法first和last
      1. 思路
        1. eq参数个数
          1. 如果个数为0,直接进行返回一个空的jq对象,所以不需要判断
          2. 直接进行判断
      2. 代码

         eq : function(i){
             /*
             * 参数的个数
             * eq参数个数
             *   1. 如果个数为0,直接进行返回一个空的jq对象,所以不需要判断
             *   2. 直接进行判断
             * */
             if(i>=0){
                 return jQuery(this[i]);
             }else{
                 return jQuery(this[this.length+i]);
             }
         },
         /*_eq : function(i){
             /!*
             * 思路:
             *   1. 没有参数,直接进行返回一个空jq对象;或是
             *   2. 有参数,进行和get一样,就是返回的时候进行包装一下成jq对象
             * *!/
             return jQuery(this.get(i));
         },*/
         first : function(){
             return this.eq(0);
         },
         last : function(){
             return this.eq(-1);
         }
        

toArray方法

  1. 作用
    1. 转换成数组对象
  2. jq的返回结果

     //转换成数组对象
     console.log($('li').toArray());
    
     var lis = document.querySelectorAll('li');
     //进行改变数组的slice的this指向
     //进行使用slice,返回的是一个数组的对象
     //,dom的this,指向前面的[]的slice方法,就可以使用数组的方法
     console.log([].slice.call(lis));
    
  3. 框架的封装jq的
    1. 代码

       toArray : function(){
                   return [].slice.call(this);
               }
       /*测试toArray的方法*/
       		console.log($('li').toArray());
      

slice方法

  1. 先列举jq中的方法
    1. slice 方法,按照指定下标截取部分元素,然后包装成jQ实例返回
  2. 检验JQ中的slice

      //先列举jq中的方法
         /*
         *slice 方法,按照指定下标截取部分元素,然后包装成jQ实例返回
         * */
         //什么也不写,
         console.log($('li'));//就是获取li标签的伪数组
         console.log($('li').slice());//也是返回li标签的伪数组
    
         console.log($('li').slice(1));//就是从第一个开始进行截取到最后
         //就是第二个[li, prevObject: jQuery.fn.init[3]],后面的这个就是上级的
         console.log($('li').slice(1, -1));
    
    
         /*
         到end()的时候再看
         //[li, li, li, prevObject: jQuery.fn.init[1]]就是上一级的链条上的数据
         console.log($('li').slice(1, -1).prevObject);
         //[li, li, li, prevObject: jQuery.fn.init[1]]  和上面的代码的执行结果是一样的
         console.log($('li').slice(1, -1).end());*/
    
    
         var arr = [1,2,7,9];
         //数组中的什么也不传,进行返回的就是数组的对象
         console.log(arr.slice());//[1, 2, 7, 9]
         console.log(arr.slice(1));//[2, 7, 9]  对的,就是从第一个开始截取到最后
         console.log(arr.slice(1,-1));/*  2 7  就是左闭合右开*/
         //在jq中,就是将剩余的数组包装成jq对象
    
    
         /*
         * 总结:
         *   1.通过js使用的slice
         *   2.再包装成jQ对象
         * */
    
  3. 总结
    1. 通过js使用的slice
    2. 再包装成jQ对象
  4. 框架封装
    1. 思路
      1. 直接进行调用数组的slice
      2. 再包装成jQ对象
    2. 实现代码

       slice : function(start,end){
           /*
           *思路:
           * 1. 直接进行调用数组的slice
           *
           * 2. 再包装成jQ对象
           * */
           //使用call转换this的指向,然后传参start,end,这个是给slice进行的传参
           return jQuery([].slice.call(this,start,end));
       }
      
    3. 测试代码

         /*
        * 测试在jq中封装的slice方法的返回值
        * */
        //什么也不传,和直接获取$('li')是一样的
        console.log($('li'));
        console.log($('li').slice());
        console.log($('li').slice(1));//取到的是2和3
        console.log($('li').slice(1,-1));//取到的是2
      

push、sort、splice方法

  1. 作用
    1. push 方法,给实例添加新元素,返回最新的length长度
    2. sort 方法,对实例中的数据进行排序,返回排序后的实例
    3. splice 方法,按照指定下标指定数量删除元素或插入元素,返回被删除的元素
  2. jq中的方法的检验

         /* 返回的就是伪数组
         * 7、push 方法,给实例添加新元素,返回最新的length长度
         * 8、sort 方法,对实例中的数据进行排序,返回排序后的实例
         * 9、splice 方法,按照指定下标指定数量删除元素或插入元素,返回被删除的元素
         * */
         /*console.log($('li'));//长度是3个li
         console.log($('li').push($('span')));//4*/
    	
         var arr = [1,3];
         console.log(arr.push(5));//返回的是长度3
         /*
    	
         * 返回的是排序li的innerHTML进行的排序
         * */
         /*console.log($('li').sort(function (a, b) {
             return a.innerHTML < b.innerHTML;
         }));*/
    	
         /*
         * [9, 2, 1, 0]
         * */
        /* var arr = [1,9,0,2];
         console.log(arr.sort(function (a, b) {
             return a < b;
         }));*/
    	
         /*
         * splice
         * splice 方法,按照指定下标指定数量删除元素或插入元素,返回被删除的元素
         * */
        /* var $li = $('li');
         //将下标为1,长度为1的数组进行删除,并且插入2, 8, 9
         console.log($li.splice(1, 1, 2, 8, 9));
         console.log($li);*/
    
  3. 封装jq中的push sort splice

         push : function(){
             /*
             * 思路:
             *  1. 直接进行调用数组的push方法,也是返回的是长度
             *  2. 改变this的指向数组的方法,就可以调用数组的push
             * */
             return [].push.apply(this,arguments);
         },
         sort : function(fn){
             return [].sort.call(this,fn);
         },
         splice : function(){
             //把obj里面的参数传值给splice的参数
             return [].splice.apply(this,arguments);
         },
         /*这种写法是直接将数组的push或是别的方法给这个实例的属性上*/
         _push: arr.push,
         _sort: arr.sort,
         _splice: arr.splice
    
  4. 对封装的代码进行测试的代码

     /*
     * 测试push
     * 测试sort
     * */
     console.log($('li').push($('span')));
    
     //测试的是对所有li标签里面的内容进行从大到小的排序
     console.log($('li').sort(function (a, b) {
         return a.innerHTML < b.innerHTML;
     }));
    
     /*测试splice*/
     var $li = $('li');
     //这个直接打印时删除的数据
     console.log($li.splice(1, 1, 90));//进行删除下标为1的元素,并且在这个位置添加90
     /*
     *
      0:li
      1:90
      2:li
     * */
     console.log($li);
    

方法的借用的几种方式

  1. 方法借用
    1. 第一种方式是通过call或是apply的方式,让fn内部的this指向p对象,
    2. 第二种方式是直接给对象添加一个fn属性,这个属性的值是函数
  2. 代码

             /*
         * 通过上下文调用模式直接进行改变this的指向
         *
         * */
         /*var obj = {};
         //将数组的this指向obj,
         //前面[]就是数组对象,也就是实例
         [].push.call(obj,1);
         //Object {0: 1, length: 1}
         console.log(obj);*/
    	
         /*
         * 把数组对象的push方法添加到obj身上
         * */
         var obj = {};
        // console.log(obj.push());//obj.push is not a function(…)
    	
         /*
         *
         * 直接将实例的push方法,给obj的push属性
         * 则obj就是push 得到的函数
         * */
         obj.push = [].push;
         console.log(obj);
         //这句代码也完成了push方法的执行,同时push内的this同样为obj
         obj.push(2);
         //Object {0: 2, length: 1}
         console.log(obj);
    	
    	
         /*
         * 进行给对象添加一个函数的值
         * */
         function fn(){
             console.log(this);
         }
         var p = {
             name : 'waxun'
         };
         //第一种方式是通过call或是apply的方式,让fn内部的this指向p对象,
         //Object {name: "waxun"}
         //fn.call(p);
    	
         //第二种方式是直接给对象添加一个fn属性,这个属性的值是函数
         p.fn = fn;
         //Object {name: "waxun"}
         p.fn();
    

end方法

  1. 作用
    1. end 方法,返回上一级链(链式编程中上一个jQ对象)
  2. 使用jq中的end进行找回断之前的链式

          /*
          end 方法,返回上一级链(链式编程中上一个jQ对象)
         * */
    	
         /*
         * 给下标为li进行设置背景色
         * 这样试用eq得到的li就是下标为1的li的元素
         * 需求:
         *   想实现链式编程,就需要找回原来直接进行获取li的个数,在这里是三个
         * */
     /*    console.log($('li').eq(1).css({
             backgroundColor: 'red'
         }));
    	
         /!*
         * 解决上面的需求
         *
         * 要想返回上级链(就是找回上一个jQ对象),需要调用end方法
         * *!/
         //[li, li, li, prevObject: jQuery.fn.init[1]]
         console.log($('li').eq(1).css({
             backgroundColor: 'red'
         }).end());*/
    
  3. 需求
    1. 目前有两个对象,可以通过一个对象找到另一个对象
    2. 解决办法
      1. 在一个对象的属性上添加一个可以找到第二个对象的标志
      2. 就可以通过一个对象可以找到另一个对象
      3. 要有关联性
    3. 实现代码

       var obj1 = {
           name : 'waxun'
       };
       var obj2 = {
           prevObj : obj1
       };
       //通过obj2 可以找到 obj1
       //Object {name: "waxun"}
       console.log(obj2.prevObj);
      	
       //需求: 要提供一个end方法供调用者使用,对象调用end,就会得到第一个对象
       //给obj2自己添加一个end()方法
       obj2.end = function(){
           return this.prevObj;
       }
       //Object {name: "waxun"}
       console.log(obj2.end());
      
  4. 什么情况下可以调用end方法
    1. 就是 返回值是jQ对象的,可以通过end进行找出上级链
    2. 代码解释

      /*
        就是  返回值是jQ对象的,可以通过end进行找出上级链
      
      
       * 报错,因为get返回的是原生DOM元素,
       * 原生DOM元素并没有继承jQ的原型,所以无法访问end方法。
       * 总结:
       *   链式编程如果断掉了,
       *   并且返回值不是jQ实例,
       *   那么链就无法再通过end方法找回上级链了。
       * */
       //$(...).get(...).end is not a function(…)
       console.log($('li').get(0).end());
      
  5. 框架中实现pushStack和end的关联进行实现链式编程
    1. 实现pushStack和end方法

         slice : function(start,end){
           /*
           *思路:
           * 1. 直接进行调用数组的slice
           *
           * 2. 再包装成jQ对象
           * */
           //使用call转换this的指向,然后传参start,end,这个是给slice进行的传参
           //return jQuery([].slice.call(this,start,end));
      
           /*
            * 因为slice改变了链式结构,并且返回的是jq对象,所以需求是
            *  可以通过end的方式进行找回断掉之前的数据,
            *  就需要断掉之前的数据进行存储一下子
            *
            *  这边slice返回的也是jQ对象,所以也给pushStsck传值过去一起处理就可以
            * */
          /* var arr = [].slice.call(this,start,end);
           return jQuery(arr);*/
      
           var arr = [].slice.call(this,start,end);
           //交给pushStack去转成jQ对象,并且添加一个存储这个调用this的属性
           return this.pushStack(arr);
       }
      
       /*实现pushStack方法,用来记录上级链的关联*/
       pushStack : function(arr){
           //$new 进行将调用传来的值转换成jQ对象,并且加上没改变链条之前的数据
           var $new = jQuery(arr);
           $new.preObj = this;//谁调用的pushStack,这个this就指向谁
           return $new;
       },
      
       /*实现end方法*/
       end : function(){
           return this.preObj;
       }
      
  6. 测试框架中写到slice关联pushStack和end

     /*
     * 测试end() 和  pushStack()
     * */
    
     /*通过slice得到数组下标从0开始,到2结束,左闭合右开的取值数据,
     两种方式得到上级的链式结构上的数据
     得到的是jq对象,可以通过直接找自己身上的preObj属性
      和通过end()方法找$('li').slice(0, 2)截取后得到的两个li对象上的preObj属性*/
    
     console.log($('li').slice(0, 2));
     //找回变之前的链条
     console.log($('li').slice(0, 2).preObj);
     console.log($('li').slice(0, 2).end());
    

jQ原型上的each方法

  1. jQ原型上的each方法
    1. 用来遍历所有的元素
    2. 要求传入一个函数,这个可以接收两个参数
    3. 第一个参数为元素的下标,第二个参数为元素
  2. jq的实现

     /*
     * 0  <li>1</li>
     * 1  <li>2</li>
     * 2  <li>3</li>
     * */
     /*$('li').each(function(index,val){
         console.log(index,val);
     });*/
    
  3. jq中的each中的this
    1. 代码及注释

       /*
       * jQ中的each中,参数是index,val,
       * 而遍历时this指向的了val的值
       * */
       /*$('li').each(function(index,val){
           console.log(index,val,this);
       })*/
      
  4. js中实现each并且改变this的指向

         /**
          *
          * @param obj 传入的对象
          * @param fn 执行完each之后的回调函数
          *
          * 注意:
          *  1.回调函数中this默认的指向是window
          *  2.jq中this的指向是和val值一样的
          *    2.1  通过call进行改变
          */
         function each(obj,fn){
             if(obj instanceof Array){
                 for(var i=0;i<obj.length;i++){
                     //这是函数调用模式,this指向window
                     //fn(i,obj[i]);
                     //要想this指向val,需要利用call或apply
                     fn.call(obj[i],i,obj[i]);
                 }
             }else{
                 for(var key in obj){
                     //函数调用模式指向的是window
                     //fn(key,obj[key]);
                     //改变this指向
                     fn.call(obj[key],key,obj[key]);
                 }
             }  }
    
  5. each方法可以中断遍历
    1. jQ的each方法,执行传入的回调时,会判断回调的执行结果,
    2. 如果结果为false,那么each会自动中断遍历
    3. 注意:这个中断是由each来实现和控制的的。
    4. 模仿jq中的each中断遍历

       /**
        * 功能: 模仿jQ中,如果回调函数返回的结果是false,就中断遍历
        *
        * @param obj 传入的对象
        * @param fn 执行完each之后的回调函数
        *
        */
       function each(obj,fn){
           if(obj instanceof Array){
               for(var i=0;i<obj.length;i++){
                  //如果回调函数执行的结果为false,就中断遍历
                   if(fn.call(obj[i],i,obj[i])==false){
                       break;
                   }
               }
           }else{
               for(var key in obj){
                   //如果回调函数执行的返回值为false,就中断遍历
                   if(fn.call(obj[key],key,obj[key])==false){
                       break;
                   }
               }
           }
       }
      	
      	
       var arr  = [1,'kaguo',false,'waxun'];
      	
       /*
       * 执行结果
       * 0 1
       * 1 "kaguo"
       * 返回给回调函数一个false,就中断了遍历
       * */
       each(arr,function(index,val){
           if(val==false){
               return false;
           }
           console.log(index,val);
       });
      
  6. 包装each

          	/*
              * 添加each方法 :
              * 1. 参数是obj和fn回调函数,通过fn进行返回index和val
              *     1.1 判断是不是数组或是伪数组,如果是,使用for循环遍历
              *     1.2 如果不是,进行使用for..in遍历
              * 2. each中this的指向是和val的值一样,所以要通过call进行改变this的指向
              * 3. 如果回调函数返回的是false,就中断遍历
              * */
             function each(obj,fn){
                 if(isObj(obj)=='Array'||isArrayLike(obj)){
                     for (var i = 0; i < obj.length; i++) {
                         if(fn.call(obj[i],i,obj[i])==false){
                             break;
                         }
                     }
                 }else{
                     for(var key in obj){
                         if(fn.call(obj[key],key,obj[key])==false){
                             break;
                         }
                     }
                 }
                 //为了jq链式编程的完整性
                 return obj;
             };
    	
    	
         each : function(fn){
                     return each(this,fn);
                 }
    
  7. 测试代码

          /*
         * 测试each方法的使用
         * 1. 真数组
         * 2. 遍历伪数组
         * 3. 遍历其他
         * */
        $('li').each(function(index,val){
            console.log(index,val);
        });
    	
         /*
         * 判断内容为空的时候,后面的内容不进行输出
         * */
    	
         //只输出了前两个,因为第三个为空,后面的不进行输出
         //进行打印最外层的是each返回了一个调用自己的对象,进行链式的完整性
         console.log($('li').each(function (index, val) {
             //里面直接是
             if (val.innerHTML == false) {
                 return false;
             }
             console.log(index, val);
         }));
    

for in

  1. 作用
    1. for in即可以遍历对象,也可以遍历数组
    2. for in 有一个特点,就是能够遍历出对象所继承的属性(这个属性必须是可枚举的)
  2. 代码(主要看被继承的也打印出来了)

      /*
     * 打印结果
     * 0 wa
     * 1 xun
     * hiN 被继承的
     *
     *
     * name waxun
     * age 12
     * hiN 被继承的
     * */
     Object.prototype.hiN = '被继承的';
     for(var key in arr){
         console.log(key,arr[key]);
     }
     for(var key in obj){
         console.log(key,obj[key]);
     }
    

call和apply的this问题

  1. 非严格模式下
    1. 如果call的是基本数据类型,那么call会自动把他包装成对象类型,
    2. 如果call的是undefined或null,那么call会自动转换为window
  2. 严格模式下
    1. call什么,就是什么
  3. 代码

     function fn(){
         console.log(this);
     }
    
     fn();//window 函数调用模式  this指向的是window
     fn.call(undefined);//this打印的是window
     fn.call(null);//this打印的是window
     fn.call(1);//this打印的是Number  基本的包装类
     fn.call('abc');//String
     fn.call([1,2]);//Array[2]
    

jQeach方法的返回值

  1. jQ中,遍历谁,就返回谁
    1. 遍历body,返回的就是body
  2. 代码

         <ul>
             <li>1</li>
             <li>2</li>
             <li>3</li>
         </ul>
         <script>
             /*
             * jQ中,遍历谁,就返回谁
             * 1. 遍历body,返回的就是body
             *
             * */
             /*$('body').each(function(){
                 console.log(this);
                 this.style.backgroundColor = '#666';
             });
         */
    	
             //将body的宽度打印出来
             console.log($('body').each(function () {
                 this.style.backgroundColor = "#666";
             }).css('width'));//1350px
         </script>
    

12/13/2016 4:04:12 PM


Similar Posts

下一篇 nodejs-day01

Comments