您可能想从简单的事情开始,例如:
function MaterObject(selector) {
this.selector = selector;
this.elements = document.querySelectorAll(selector);
}
现在通过 MasterObject.prototype 添加功能:
MasterObject.prototype = {
getLength: function() {
return this.elements.length;
},
refresh: function() {
this.elements = document.querySelectorAll(this.selector);
return this;
},
addMore: function(selector) {
this.selector = this.selector + ',' + selector;
this.refresh();
return this;
}
}
等等。要启动它:
function $(selector) {
return new MasterObject(selector);
}
以上缺乏功能测试,因此很脆弱。
请注意,大部分 jQuery 都是重载的,因此它需要测试给出的内容,然后决定处理结果(想到著名的“isArray”案例)。调用方法可能会对选择器选择的所有元素或仅第一个元素执行某些操作。向方法传递字符串、对象或任何内容都可能完全改变方法的作用。
请注意,函数可以返回this
,因此可以链接方法。但问题是(对于库设计者和用户来说)是确定哪些应该是可链接的,哪些不应该,例如
var $x = $('div');
// addMore is chainable, getLength isn't
$x.addMore('p').getLength();
编辑
如果您希望您的“jQuery”对象成为一个数组,那么您必须将所有要继承的方法添加到 Array.prototype,这不是一个好主意。没有其他办法,你不能创建一个数组对象并将你自己的原型对象插入到它的[[Prototype]]
链中,一个数组实例将直接继承自 Array.prototype。
您可以做的最好的是将元素 NodeList 转换为数组(就像您在 OP 中所做的那样)并在其上调用类似数组的方法(注意,因此,选择器可能不代表元素数组的内容):
function MasterObject(selector) {
this.selector = selector;
this.elements = [];
}
MasterObject.prototype = {
...
refresh: function() {
this.elements = [];
var els = document.querySelectorAll(this.selector);
for (var i=0, iLen=els.length; i<iLen; i++) {
this.elements[i] = els[i];
}
return this;
},
pop: function() {
return this.elements.pop();
},
此类更改可能会反映在 DOM 中(在这种情况下,选择器应该与内容同步,而不必通过 qSA 再次选择它):
popElement: function() {
var el = this.elements.pop();
el.parentNode.removeChild(el);
return el;
},
...
};
function $(selector) {
var newObj = new MasterObject(selector);
newObj.refresh();
return newObj;
}