首页 > 解决方案 > 了解链式函数,如何返回类似 jquery 的元素本身,如何避免“......不是函数”

问题描述

完全是实验性的,仅用于学习我正在尝试重新发明轮子,一个名为 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');,这真的很酷。

对于那些感兴趣的人,这里是今天的完整脚本快照,包括css()and attr(),并包括缺少的 jquery 函数id()

我的问题是:

请不要问我为什么要做这一切,因为我提到这是为了学习和理解

谢谢。

标签: javascriptjquerychained

解决方案


我怎样才能让这个函数像 jquery 一样返回元素本身var elm = $('div#test');,现在我要取回整个对象。

jQuery 总是给你一个完整的 jQuery 对象。如果您指的是您定义的方法 ( addClass, ...) 如何不与对象一起出现在浏览器控制台中,这是通过与原型共享这些属性而不是为每个对象创建一组新函数来实现的。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 上的数组一样显示,并且$('div#test')[0]像 jQuery 那样可以通过索引访问元素,则将元素分配给这些索引并为您的集合提供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 上显示为数组,您可以进行定义splice方法的怪异 hack(在 2019 年仍然适用) ,即使它不做与数组相同的事情……或做任何事情全部:

class MyElementCollection {
    // ⋮

    splice() {
        throw new Error('Not implemented');
    }
}

$(...).animate如果我正在使用当前未包含在此函数中的方法,例如$('div#test').addClass('newclass').animate({top:'2.3em',background:'red'});,因为animate()目前未实现,我如何编写回退函数,以防止收到错误消息,例如is not a function。有php一个__get()函数,javascript中有类似的东西吗?

可以在 JavaScript 中使用代理来做到这一点,但我不推荐它——它不是很干净。(您的对象将假装拥有所有属性,而不仅仅是 jQuery 中您尚未实现的属性,并且在原型上不会找到它们的列表。代理也会带来性能和可理解性的损失。)取而代之的是,考虑为所有未实现的东西分配相同的实现:

class MyElementCollection {
    // ⋮
}

const notImplemented = () => {
    throw new Error('Not implemented');
};

['animate', …].forEach(name => {
    MyElementCollection.prototype[name] = notImplemented;
});

推荐阅读