jquery的微小实现

时间:2015-04-15 11:28:53

标签: javascript jquery this each

1)我有一个在Javascript上实现jQuery的任务。 但出于某种原因,我的方法都不起作用。 例如,当我写

$('.a').each(function (index) {$(this).append('<b>' + index + '</b>')})

它返回

DOMException:无法执行&#39; querySelectorAll&#39; on&#39; Document&#39;:&#39; [object Object]&#39;不是有效的选择器。

我也不能在其他功能中使用this.each。例如,如果我在内部使用每个而不是forEach,那么它将无效。


<script type="text/javascript">
(function() {
  function $(selector) {
    if (this instanceof $) return this.search(selector)
      return new $(selector);
  }
  $.prototype = {
    constructor: $,
    length: 0,

    search: function(selector) {
      var that=this;
      var elems=Array.prototype.slice
          .call(document.querySelectorAll(selector));
      elems.forEach(function(x,i){that[i]=x;});
      this.length = elems.length;
      return this;
    },

    append: function(text) {
      if (text instanceof $) {
        this[0].appendChild(text[0]);
        for(var i = 1; i < this.length-1; i++) {
          var p = text[0].cloneNode(true);
          this[i].appendChild(p);
        }
      } else Array.prototype.slice
          .call(this).forEach(function(x){
              x.innerHTML  =  x.innerHTML  +  text;
          });

      return this;
    },  

    each: function(callback){
      for (var i=0;i<this.length;i++){
        this[i]=callback.call(this,this[i])
      };
      return this;
    },

  }
  window.$ = $;
}());

2 个答案:

答案 0 :(得分:5)

  

例如,当我写

$('#id').each(function (index) {$(this).html('<b>' + index + '</b>')})
     

它返回

     

DOMException:无法执行&#39; querySelectorAll&#39; on&#39; Document&#39;:&#39; [object Object]&#39;不是有效的选择器。

您在$(this)回调中正在each进行操作。因此$调用this设置为DOM元素,而不是instanceof $,因此您调用new $(selector)传递DOM元素。最终调用this.search(selector),其中selector是DOM元素。然后你拨打querySelectorAll(selector)。 QSA接受字符串,而不是DOM元素,因此元素会转换为字符串"[object Object]"(或者在某些引擎上转换为"[object HTMLElement]"),然后失败。

您可以使用浏览器中内置的调试程序逐个语句来逐步诊断这些错误。如果您出于某种原因重新实现jQuery,那么您需要养成这样做的习惯:大量使用调试器,找出错误并修复它。

在这种情况下,例如,您要检测selector不是字符串并处理该字符串,例如像这样模糊的东西:

search: function(selector) {
  var that=this, elems;
  if (typeof selector === "string") {
    elems = Array.prototype.slice.call(document.querySelectorAll(selector));
    elems.forEach(function(x,i){that[i]=x;});
    this.length = elems.length;
  } else {
    this[0] = selector;
    this.length = 1;
  }
  return this;
},

但是,除了那些你将需要调试器的其他东西之外,还会有很多其他的东西。

答案 1 :(得分:0)

这适用于您的用例,但实现所有边缘情况会更复杂一些:

(function() {
  function $(selector) {
    if (!(this instanceof $)){//forgot new
      return new $(selector);
    }
    if(typeof selector === 'string'){ 
      return this.search(selector);
    }
    //assuming selector is a dom object
    this[0]=selector;
    this.length=1;
  }
  $.prototype = {
    constructor: $,
    length: 0,

    search: function(selector) {
      var that=this;
      var elems=Array.prototype.slice
          .call(document.querySelectorAll(selector));
      elems.forEach(function(x,i){that[i]=x;});
      this.length = elems.length;
      return this;
    },
    append: function(text) {
      if (text instanceof $) {
        this[0].appendChild(text[0]);
        for(var i = 1; i < this.length-1; i++) {
          var p = text[0].cloneNode(true);
          this[i].appendChild(p);
        }
      } else {
           this.each(function(x){
              this.innerHTML  =  this.innerHTML  +  text;
          });
      }
      return this;
    },  
    // callback is called with the invoking object to be the dom element
    each: function(callback){
      for (var i=0;i<this.length;i++){
        this[i]=callback.call(this[i],i);
      };
      return this;
    },

  }
  window.$ = $;
}());
$('.a').each(function (index) {return $(this).append('<b>' + index + '</b>')})