完全实验性的,仅用于学习我试图重新发明轮子,一个叫做jquery的轮子。这样做的最初目的是了解可链接的功能。所以我写了一个这样做的函数,就我所见,我也是如此:(有点缩短)
var $ = function(s) {
var el = document.querySelectorAll(s);
var myobj = {
addClass(className) {
el.forEach(elem => {elem.classList.add(className)});
return this;
},
toggleClass(className) {
el.forEach(elem => {elem.classList.toggle(className)});
return this;
},
removeClass(className) {
el.forEach(elem => {elem.classList.remove(className)});
return this;
},
html(html) {
if (typeof html == 'string') {
el.forEach(elem => {elem.innerHTML = html});
return this;
} else {
return el[0].innerHTML;
}
}
};
return myobj;
};
(这真是一个有效的例子)现在我可以使用类似jquery的语法来操作类和元素的html(或元素的节点列表),如:$('#test').html('new html content');
或链接像$('a').html('my new link').addClass('newclassname');
,这真的很酷。
对于那些感兴趣的人,这里是完整的script snapshot of today,包括css()
和attr()
,包括缺少的jquery函数id()
。
我的问题是:
var elm = $('div#test');
一样返回jquery-like元素本身,现在我回到了整个对象。$(...).animate is not a function
等错误消息,如果我使用的是当前未在此函数中涵盖的方法,如$('div#test').addClass('newclass').animate({top:'2.3em',background:'red'});
,因为animate()
未实现在这一刻。在php
有一个__get()
函数,javascript中有类似的东西吗?请不要问我为什么要这样做,因为我提到它是为了学习和理解
谢谢。
我怎样才能让这个函数像
var elm = $('div#test');
一样返回jquery-like元素本身,现在我回到了整个对象。
jQuery总是会给你一个完整的jQuery对象。如果您指的是您定义的方法(addClass
,...)如何与浏览器控制台中的对象一起出现,则通过与prototype共享这些属性而不是为每个对象创建一组新函数来实现。 ES6类是一种方便的方法,可以使构造函数允许您使用方法定义原型并创建从中继承的对象:
class MyElementCollection {
constructor(el) {
this.el = el;
}
addClass(className) {
this.el.forEach(elem => {elem.classList.add(className)});
return this;
}
// ⋮
}
var $ = function(s) {
var el = document.querySelectorAll(s);
return new MyElementCollection(el);
};
然后,如果你想让它像Firefox上的数组一样显示并且像jQuery那样可以通过索引$('div#test')[0]
访问元素,那么你可以将元素分配给这些索引并为你的集合提供length
:
class MyElementCollection {
constructor(el) {
el.forEach((elem, i) => {
this[i] = elem;
});
this.length = el.length;
}
each(action) {
for (let i = 0; i < this.length; i++) {
action(this[i]);
}
}
addClass(className) {
this.each(elem => {elem.classList.add(className)});
return this;
}
// ⋮
}
然后,如果你希望它在Chrome上显示为一个数组,那你就会做defining a splice
method的奇怪的黑客攻击(仍然适用于2019年),即使它没有做它在数组上做的事情......或者做任何事情:
class MyElementCollection {
// ⋮
splice() {
throw new Error('Not implemented');
}
}
我如何编写一个回退函数,以防止像
$(...).animate
这样的错误消息不是函数,如果我使用的是当前未在此函数中涵盖的方法,如$('div#test').addClass('newclass').animate({top:'2.3em',background:'red'});
,因为此时animate()
尚未实现。在php
有一个__get()
函数,javascript中有类似的东西吗?
你可以用JavaScript中的proxies做到这一点,但我不推荐它 - 它不是很干净。 (您的对象将假装拥有所有属性,而不仅仅是您尚未实现的jQuery中存在的属性,并且不会在原型上找到它们的列表。代理也会带来性能和可理解性惩罚。) ,考虑为所有未实现的东西分配相同的实现:
class MyElementCollection {
// ⋮
}
const notImplemented = () => {
throw new Error('Not implemented');
};
['animate', …].forEach(name => {
MyElementCollection.prototype[name] = notImplemented;
});
看看jquery的github repo。相关文件如下:
https://github.com/jquery/jquery/blob/master/src/core.js
https://github.com/jquery/jquery/blob/master/src/core/init.js
jQuery以比我在这里做的更复杂的方式做它的东西,所以这只是一个基本的解释。
jQuery
函数(以及它的$
别名)在其函数体中调用new jQuery.fn.init(selector, root)
。这将从jQuery collection
创建一个新的jQuery.prototype
(这是他们在文档中使用的术语)。该原型具有所有常用的jQuery方法(如on
,find
,animate
等)。
他们这样做:
function jQuery (selector, root) {
return new jQuery.fn.init(selector, root);
}
jQuery.fn = jQuery.prototype = { /* skipped */ }
jQuery.fn.init = function (selector, root) { /* skipped */ }
jQuery.fn.init.prototype = jQuery.fn;
这里的关键是最后一行,他们使jQuery.prototype
也是prototype
的jQuery.fn.init
(不要被fn
弄糊涂,它只是他们使用的另一个别名,所以他们不必一直输入prototype
)。
当您扫描jQuery.fn.init
构造函数时,您会注意到它们将所有匹配的DOM元素按其索引存储到新集合中。简化:
jQuery.fn.init = function (selector, root) {
let elms = Array.from(root.querySelectorAll(selector));
elms.forEach((el, index) => {
this[index] = el;
}, this);
}
他们做了很多东西,但这基本上解释了jQuery集合是什么:一个自定义类型的对象,部分看起来像一个NodeList
,但有一个自定义的prototype
,它附加了所有的jQuery方法。
这意味着,您的第一个问题基于错误的假设:使用$('div#test')
将返回带有单个元素的jQuery集合。你永远不会从jQuery获得“原始”DOM节点。
至于你的第二个问题:你可以使用代理。