试图实现与jQuery

时间:2017-06-08 14:44:52

标签: javascript jquery html

我正在尝试实现类似于jQuery的东西 基本上,每当我使用DOM元素做某事时,我都想使用包装器对象的方法而不是直接操作DOM。

这是我到目前为止所拥有的

HTML:

<a href='#!'></a>

JS:

var dd = function(selector)
{
    return new dd.prototype.constructor(selector);
}
dd.prototype =
{
    constructor: function(selector)
    {
        var nodes = document.querySelectorAll(selector);

        for(var i = 0; i < nodes.length; i++)
            this[i] = nodes[i];

        this.length = nodes.length;
        return Array.prototype.slice.call(this);
    },
    addClass: function(cl)
    {
        alert('a');
    }
};

var a = dd('[href="#!"]');
a.addClass('asd');

问题:

  • 我在浏览器控制台中收到错误消息a.addClass is not a function
  • dd('a') instanceof dd === false $('a') instanceof $ === true,所以我知道我的逻辑在某种程度上是错误的。
可悲的是,我不太明白我做错了什么。

3 个答案:

答案 0 :(得分:2)

虽然重新发明轮子不是一个好主意, 以下内容可以帮助您。

考虑jQuery支持自定义构建, 所以,首先,看看https://github.com/jquery/jquery#how-to-build-your-own-jquery

var dd = (function() {
  function dd(selector) {
    // class call check
    if(!(this instanceof dd)) {
      return new dd(selector);
    }

    Array
      .from(document.querySelectorAll(selector), (el, i) => {
        this[i] = el;
      })
    ;
    
    Object
      .defineProperty(this, 'length', {
        get: () => Object.keys(this).length
      })
    ;
  }
  
  dd.prototype.forEach = function(cb) {
    Object
      .keys(this)
      .forEach(i => {
        cb(this[i], i)
      })
    ;
    
    return this;
  }
  
  dd.prototype.addClass = function() {
    this.forEach(el => el.classList.add(...Array.from(arguments)));

    
    return this;
  }
  
  dd.prototype.removeClass = function() {
    this.forEach(el => el.classList.remove(...Array.from(arguments)));
    
    return this;
  }

  return dd;
})();

var odd = dd('strong');
var even = dd('span');

window.setTimeout(() => odd.addClass('foo'), 2000);
window.setTimeout(() => even.addClass('baz'), 3000);

console.log('odd', odd.length);
console.log('even', even.length);
.cntr strong,
.cntr span {
  display: inline-flex;
  width: 20px;
  height: 20px;
  transition: 250ms all linear;
  margin: 2px;
  border: 1px solid cyan;
  background: lightseagreen;
}

.cntr .foo { background: yellow; }
.cntr .baz { background: orange; }
<section class="cntr">
	<strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span>
</section>

答案 1 :(得分:1)

不确定你想要实现的目标但是现在就看看出了什么问题。

1)您在constructor上调用new,然后返回return Array.prototype.slice.call(this);,因此您在a中获得的是一个数组。显然,数组不知道你的函数addClass 2)如果您注释掉数组切片部分,您将返回this设置为constructor的对象,但addClass的{​​{1}}对象未添加prototype {1}}。为此,您需要添加constructor,如下所示:

addClass

通过这些更改,您可以获得警报,并希望可以继续进行。 总的来说这些变化:

dd.prototype.constructor.prototype.addClass = function (cl) {
            alert('a');
        }
var dd = function(selector) {
  return new dd.prototype.constructor(selector);
}
dd.prototype = {
  constructor: function(selector) {
    var nodes = document.querySelectorAll(selector);

    for (var i = 0; i < nodes.length; i++)
      this[i] = nodes[i];

    this.length = nodes.length;
    //return Array.prototype.slice.call(this);
  },
  //addClass: function (cl) {
  //    alert('a');
  //}
};
dd.prototype.constructor.prototype.addClass = function(cl) {
  alert('a');
}
var a = dd('[href="#!"]');
a.addClass('asd');

答案 2 :(得分:1)

您正在混合类和对象工厂。你无法双管齐下。

你要么(jQuery风格):

function dd(selector) {
    return {
        addClass: function () {/**/}
    };
}

var a = dd('[href="#!"]');
a.addClass('asd');

或者你这样做:

function dd(selector) {
    this.selector = selector;
}
dd.prototype.addClass = function () {/**/};

var a = new dd('[href="#!"]');
a.addClass('asd');

请注意,这不会像jQuery那样自动生成a instanceof Array。你需要一些黑魔法来做到这一点。