为什么 jQuery 插件中是 this 而不是 $(this)

Bra*_*roy 5 jquery jquery-plugins

文档告诉我们:

假设我们想要创建一个插件,使一组检索到的元素中的文本变为绿色。我们所要做的就是将一个名为 greenify 的函数添加到 $.fn 中,它将像任何其他 jQuery 对象方法一样可用。

$.fn.greenify = function() {
    this.css( "color", "green" );
};


$( "a" ).greenify(); // Makes all the links green.
Run Code Online (Sandbox Code Playgroud)

请注意,要使用另一种方法 .css(),我们使用 this,而不是 $( this )。这是因为我们的 greenify 函数与 .css() 是同一对象的一部分。

我不明白最后一段。该函数传递给什么this?为什么不$(this)引用 jQuery 对象呢?我们不习惯$(el).css()在 jQuery 中设置 CSS 吗?那为什么不在插件中呢?

Gru*_*ndy 2

让我们尝试更深入地了解一下:

让我们尝试生成一个非常简化的版本库,例如 jQuery,并将其命名为microM

(function(global) {
  //function analog jQuery
  var microM = function(context) { 
    return new microM.fn.init(context);
  }

  //init prototype
  microM.fn = microM.prototype = {
    version: '0.0.0.1',
    constructor: microM
  };

  //function for initialize context
  var init = microM.fn.init = function(context) {
    if (context instanceof microM) context = microM.extend([], context.context);

    this['context'] = [].concat(context);
    return this;
  };

  init.prototype = microM.fn;

  //add function extend to prototype and as static method
  microM.extend = microM.fn.extend = function() {
    if (arguments.length == 2) {
      var target = arguments[0],
        source = arguments[1];
    } else {
      var target = this,
        source = arguments[0];
    }
    for (var key in source) {
      target[key] = source[key];
    }

    return target;
  }

  //extend microM prototype with a few simple function
  microM.fn.extend({
    min: function() {
      return Math.min.apply(Math, this.context);
    },
    max: function() {
      return Math.max.apply(Math, this.context);
    },
    pow: function(exponent) {
      for (var i = 0, len = this.context.length; i < len; i++) {
        this.context[i] = Math.pow(this.context[i], exponent);
      }
      return this;
    },
    get: function() {
      return microM.extend([], this.context);
    },
    map: function(callback) {//a function that takes a callback
      var result = [];
      for (var i = 0, len = this.context.length; i < len; i++) {
        var callbackResult = callback.call(this.context[i], this.context[i], i);
        if (callbackResult instanceof microM) result = result.concat(callbackResult.get());
        else result = result.concat(callbackResult);
      }
      return microM(result);
    }
  });

  //looks a like jQuery :-)
  global.microM = microM;
})(window);
Run Code Online (Sandbox Code Playgroud)

所以我们有一个最简单的库,看起来像 jQuery。现在我们要向其添加“插件”,例如函数square

就像在 jQuery 中一样,我们将其添加到原型中,或者在我们的例子中添加与原型相同的fn :

microM.fn.square = function() {
  return this.pow(2);
}
Run Code Online (Sandbox Code Playgroud)

这里我们可以直接调用pow,因为在这种情况下我们的microM实例以及microM.prototype中的所有函数都可以直接使用;

但是,当我们调用在回调内部接受回调的映射函数时,这将是具体元素,例如 Number 原语,因为我们这样称呼它

callback.call(this.context[i], this.context[i], i);
Run Code Online (Sandbox Code Playgroud)

调用函数中的第一个参数是thisArg

也许下面的代码片段可以澄清我混乱的解释:-)

(function(global) {
  //function analog jQuery
  var microM = function(context) { 
    return new microM.fn.init(context);
  }

  //init prototype
  microM.fn = microM.prototype = {
    version: '0.0.0.1',
    constructor: microM
  };

  //function for initialize context
  var init = microM.fn.init = function(context) {
    if (context instanceof microM) context = microM.extend([], context.context);

    this['context'] = [].concat(context);
    return this;
  };

  init.prototype = microM.fn;

  //add function extend to prototype and as static method
  microM.extend = microM.fn.extend = function() {
    if (arguments.length == 2) {
      var target = arguments[0],
        source = arguments[1];
    } else {
      var target = this,
        source = arguments[0];
    }
    for (var key in source) {
      target[key] = source[key];
    }

    return target;
  }

  //extend microM prototype with a few simple function
  microM.fn.extend({
    min: function() {
      return Math.min.apply(Math, this.context);
    },
    max: function() {
      return Math.max.apply(Math, this.context);
    },
    pow: function(exponent) {
      for (var i = 0, len = this.context.length; i < len; i++) {
        this.context[i] = Math.pow(this.context[i], exponent);
      }
      return this;
    },
    get: function() {
      return microM.extend([], this.context);
    },
    map: function(callback) {//a function that takes a callback
      var result = [];
      for (var i = 0, len = this.context.length; i < len; i++) {
        var callbackResult = callback.call(this.context[i], this.context[i], i);
        if (callbackResult instanceof microM) result = result.concat(callbackResult.get());
        else result = result.concat(callbackResult);
      }
      return microM(result);
    }
  });

  //looks a like jQuery :-)
  global.microM = microM;
})(window);
Run Code Online (Sandbox Code Playgroud)
microM.fn.square = function() {
  return this.pow(2);
}
Run Code Online (Sandbox Code Playgroud)