jQuery源码阅读笔记(4)

原型上的属性与方法

核心函数基础构造好后,就可以给原型添砖加瓦了

实例对象与构造函数共用的属性与方法,不过主要还是提供给所有实例对象使用

为了精简,示例代码并不会带着原型,而是以代码就在原型对象当中的方式展示,如

JQ.fn = JQ.prototype = { 
	//...
    length: 0,//只展示属性和属性值,其他省略
    //...
    fn() {},//函数以对象简写形式展示,其他省略
    //...
}
jquery
  • 概述:一个属性,可以获得jQuery版本号,而平时可以用于分辨是否为一个**$实例对象**

    jquery: '1.0.0'
    
length
  • 概述:默认长度,访问空实例对象的length属性时,给一个0好过undefined

    length: 0
    
pashStack(elem)
  • 概述:返回一个新**$对象**,新对象有一个指针,可以回退至调用对象

  • 解析:

    • 为返回的新对象添加prevObject属性

    • 配合end()方法和链式调用,进退自如

    • 手册上没有查询到此方法,不过主要也是内部使用的

      pushStack (elem) {
          //合并数组法,将新对象与参数合并
          //使用constructor()是为了减少作用域查找
          const rest = merge(this.constructor(), elem)
          //给新对象添加指针属性
          rest.prevObject = this;
          //返回新对象
          return rest;
      }
      
end()
  • 概述:回退,与上者打配合

  • 解析:

    • 多数是为了链式不断,反复横跳

    • 为什么要这么玩?可以不重复创造对象,提高效率

      const $nav = $('nav');
      $('button').eq(0).click(() => {
          $nav.show(1000, () => {
              console.log('show');
          });
      }).end().eq(1).click(() => {
          $nav.hide(1000, () => {
              console.log('hide');
          });
      }).end().eq(2).click(() => {
          $nav.toggle(1000, () => {
              console.log('toggle');
          });
      }).end().eq(3).click(() => {
          $nav.stop();
      });
      
      //此处为实现
      end() {
          //巧用或来达到筛选的目标,没有则返回一个新的空对象
          return this.prevObject || this.constructor();
      }
      

现在添加几个真数组的原型方法,事实上在核心函数当中,也多次用到了push(),不过这并不是最优方案

在源码当中,是提前就将空数组和方法都准备好了,免于不断创造字面量的空数组,添加下面几个方法

  • push()

  • sort()

  • slice()

  • splice()

  • includes()

    includes()为ES6新加入的方法,此处是自用,官方并没有这一套

    //空数组,利用它获得原型方法的引用
    const arr = [],
          push = arr.push,
          sort = arr.sort,
          slice = arr.slice,
          splice = arr.splice,
          includes = arr.includes;
    
    const jQuery = function() {
        //...
    }
    

    除了slice(),其他方法可以直接写入原型当中,正常引入即可

    关于如何借用真数组的原型方法,此处只能广泛的说,通过this

slice(start, [end])
  • 概述:选取数组的子集,包装$对象并返回

  • 解析:

    • 之所以它需要处理,是因为返回值是$对象而不是真数组形式

    • 而且,返回的对象有prevObject会跳,其他保持一致

    • 也只有它是写在手册上的,其他几个是内部使用

      //分割JQ对象并返回,且新对象创建指针属性方便end跳回
      slice() {
          //因为apply第二个参数为数组,而arguments是一个伪数组,放入便是解构
          return this.pushStack(slice.apply(this, arguments));
      }
      
toArray()
  • 概述:将$对象转换为真数组并返回

    //是直接使用的slice方法,改变this,不提供参数
    toArray() {
        return slice.call(this);
    },
    
get([index])
  • 概述:取得其中一个匹配的元素

  • 解析:

    • 与数组访问元素的形式一致,不过可以接收负数

    • 事实上,这个方法几乎没啥亮点,我个人几乎是没用过

    • 不过参数填写-1可以优雅获得最后一个元素这倒是行

      get(index) {
          //没有参数或者为null时返回一个数组
          if (index == null) {
              return this.toArray();
          }
          //判断是否是一个有效数字
          if (isNumeric(index)) {
              return index < 0 ? this[this.length + index * 1] : this[index];
          }
      },
      

      此处我加了点料,可以处理字符串形式的负数,官方是不玩这一点的

eq(index)
  • 概述:取得其中一个匹配的元素,包装为$对象并返回

  • 解析:

    • 与上者很像,不过这位使用频率那就高多了

    • 返回的对象有回跳属性

      eq(index) {
          //调用者的长度
          const n = this.length;
          //对参数做一个处理,因为接受负数
          const j = index * 1 + (index < 0 ? n : 0);
          //参数大于0的同时还要小于索引,否返回一个空
          //使用pushStack方法创建一个新对象,将获取的对象返回
          return this.pushStack(j >= 0 && j < n ? [this[j]] : []);
      },
      

      此处不能使用get()来帮助筛选,对于空参数get是返回全部,而eq()是空

first() & last()
  • 概述:前者是获得第一个元素,后者是获得最后一个元素

  • 解析:

    • 两者只是eq()简化写法,就放在一起说了

    • 虽然显得反而更长,不过也提高了语义

      //第一个
      first() {
          return this.eq(0);
      },
      //最后一个
      last() {
          return this.eq(-1);
      },
      
odd() & even()
  • 概述: 前者获得奇数元素,后者获得偶数元素,以$对象形式返回

  • 解析:

    • 手册上没有记载,但存在系列

    • 不是选择器形式,而是原型方法

    • 使用了工具函数grep()

      //奇数
      odd() {
          return this.pushStack(grep(this, (_elem, i) => {
              return i % 2;
          }));
      },
      //偶数
      even() {
          return this.pushStack(grep(this, (_elem, i) => {
              return (i + 1) % 2;
          }));
      },
      

      有学到一点是,下划线命名,表示了不会使用,或者说不建议使用

each(callback) & map(callback)
  • 概述:遍历函数,前文已说明,此处不多做介绍

  • 解析:

    • 前文已创建好了静态方法,在这里就能直接调用了

    • 之前是因为一些方法还没写,所以就没有添加至原型上,现在回补

    • each()没有变化,但是map()就有所不同

    • 以下是原型与构造函数相比,不同的几点

      • map()没有第三个参数
      • 回调函数中的this有指向
      • 回调函数的参数位置不同
      • 返回值是$对象,且有回跳属性
      //遍历法
      each(callback) {
          return jQuery.each(this, callback);
      },
      //改变this指向,且改变参数位置,而且返回值需要变成JQ对象
      map(callback) {
          /*
           * 此处的顺序是这样
           * 先进行map遍历,内部按常规套路运行,
           * 最后获得的数组拉去工厂加工,称为新对象且有指针*/
          return this.pushStack(jQuery.map(this, function (ele, i) {
              return callback.call(ele, i, ele);
          }));
      },
      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值