如何复制jQuery的$(this)?

时间:2016-07-08 23:03:25

标签: javascript jquery this

我正在创建一个迷你库,试图至少部分地重建jQuery用于学习目的的方式,并更好地理解面向对象编程的工作原理。

我已经重新创建了jQuery种方法clickaddClass,但当我将它们称为:

$(".class1").click(function() {
    $(".class1").addClass("class2"); // Works, but it adds class2 to all elements
    this.addClass("class2"); // Doesn't work
});

我得到Uncaught Errorthis.addClass不是函数,这是正常的,因为我不能访问其他对象的方法。

jQuery中$(this)如何表示触发事件的DOM元素,因此在我的情况下我可以使用它仅将class2添加到元素单击而不是所有具有类class1的元素?

P.S:我试过阅读jQuery文件,但我觉得这些水域对我来说太深了。

修改

  1. 我一直很感谢Stack Overflow提供的所有答案和帮助,但告诉我使用$(this)代替this并不能解决我的问题,因为{{1}我的代码中不存在。我正在努力学习如何创建类似jQuery的$(this)&它背后的逻辑是什么。

  2. $(this)方法定义如下:

  3. click

5 个答案:

答案 0 :(得分:2)

您需要使用callapplybind或其中某些组合来设置回调的上下文到DOM节点。这是jquery的each方法的一个人为设想的例子,它使用call设置回调的上下文:

var $ = {
   each: function(selector, callback) {
      var collection = Array.from(document.querySelectorAll(selector));
      collection.forEach(function(element, index) {
         // the magic...
         callback.call(element, index, element);
      });
   }
}

$.each('.foo', function(idx, el) {
   console.log(this.textContent);
});

答案 1 :(得分:1)

this是本机JavaScript元素,仅公开本机API。您需要将它传递给jQuery构造函数才能访问jQuery的API

$(this).addClass("class2"); // This will work

答案 2 :(得分:0)

一种可能的方式(只接受选择器):

$ = function(selector) {
    this.elements = '';//Select the element(s) based on your selector

    this.addClass = function(klass) {
        //apply your klass to you element(s)
        return this;
    };

    this.click= function(handler) {
        //Attach click event to your element(s)            
        return this;
    };

    return this;

};

请记住,这只是一个例子。

修改1:

click方法中,您在错误的范围内调用处理程序(匿名函数范围)。您需要使用外部范围:

$.prototype = {
    click: function(callback) {
        console.log(this.length);
        var _self = this;
        for (var i = 0; i < this.length; i++) {
            this[i].onclick = function(event) {
                //this here presents the anonymous function scope
                //You need to call the handler in the outer scope
                callback.call(_self, event);
                //If you want to call the handler in the Element scope:
                //callback.call(_self[i], event); 
            }
        }
    }
}

注意:在您的示例中,this.addClass("class2");不起作用,因为jQuery调用Element范围而不是jQuery范围内的Click处理程序。因此,this显示Element没有addClass方法;

答案 3 :(得分:0)

好的,我现在明白你的问题。让我试着再次帮助你。

当你将它提供给选择器时,jQuery不知道你使用什么DOM元素。它不解析它或其他东西。只需将其保存到内部属性即可。

非常简化的代码:

$ = function(e) {

    // finding object. For example "this" is object
    if (typeof e !== 'object' || typeof e.className === 'undefined') {
        if (typeof e == 'string') {
            if (e[0] == '#') {
                e = document.getElementById(e.substring(1));
            } else if (e[0] == '.') {
                e = document.getElementsByClassName(e.substring(1))[0];
            } else {
                // ... etc
            }
        }
        // ... etc
    }

    var manager = {
        elem: e,
        addClass: function(newClass) {
            manager.elem.className = manager.elem.className + ' ' + newClass;
            return manager;
        },
        click: function(callback) {
            // here is just simple way without queues
            manager.elem.onclick = function(event) {
                callback.call(manager, event);
            }
        }
    }

    return manager;

}

答案 4 :(得分:0)

凭借额外1。5年的经验,这个问题变得相当容易。

  1. 更改$,这样除了字符串选择器外,它还可以接受HTML元素。
  2. 创建包含给定HTML元素的对象的新实例。
  3. addClass作为上下文调用。
  4. <强>代码:

    ;(function() {
      /* The object constructor. */
      function ElementList(arg) {
        /* Cache the context. */
        var that = this;
        
        /* Save the length of the object. */
        this.length = 0;
    
        /* Check whether the argument is a string. */
        if (typeof arg == "string") {
          /* Fetch the elements matching the selector and inject them in 'this'. */
          [].forEach.call(document.querySelectorAll(arg), function(element, index) {
            that[index] = element;
            that.length++;
          });
        }
    
        /* Check whether the argument is an HTML element and inject it into 'this'. */
        else if (arg instanceof Element) {
          this[0] = arg;
          this.length = 1;
        }
      }
    
      /* The 'click' method of the prototype. */
      ElementList.prototype.click = function(callback) {
        /* Iterate over every element and set the 'click' event. */
        [].forEach.call(this, function(element) {
          element.addEventListener("click", function(event) {
            callback.call(this, event);
          });
        });
      }
    
      /* The 'addClass' method of the prototype. */
      ElementList.prototype.addClass = function(className) {
        /* Iterate over every element. */
        [].forEach.call(this, function(element) {
          /* Cache the classList of the element. */
          var list = element.classList;
    
          /* Add the specified className, if it doesn't already exist. */
          if (!list.contains(className)) list.add(className);
        });
      }
    
      /* The global callable. */
      window.$ = function(arg) {
        return new ElementList(arg);
      }
    })();
    
    /* Example */
    $("#b1").click(function() {
      $(this).addClass("clicked");
      console.log(this);
    });
    <button id="b1">Click</button>