原型上的属性与方法
核心函数基础构造好后,就可以给原型添砖加瓦了
实例对象与构造函数共用的属性与方法,不过主要还是提供给所有实例对象使用
为了精简,示例代码并不会带着原型,而是以代码就在原型对象当中的方式展示,如
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); })); },
-