Why this and not $(this) in jQuery plugins

后端 未结 2 1601
陌清茗
陌清茗 2021-01-13 18:45

The docs tell us:

Let\'s say we want to create a plugin that makes text within a set of retrieved elements green. All we have to do is add a functio

相关标签:
2条回答
  • 2021-01-13 19:22

    Don't we use $(el).css() to normally set CSS in jQuery?

    Yes, when in the context of an element.

    However in

    $.fn.greenify = function() {
        // 'this' is a jQuery object at this point - with all the jQuery functions
        this.css( "color", "green" );
    };
    

    greenify is part of the same object that has the css function.

    Somewhere else, there is a

    $.fn.css = function() {
           ...
        };
    

    Both css and greenify are part of the prototype($.fn)

    See jQuery: What's the difference between '$(this)' and 'this'? and https://remysharp.com/2007/04/12/jquerys-this-demystified

    0 讨论(0)
  • 2021-01-13 19:35

    Let's try see a bit deeper:

    let's try generate a very simplified version lib, like jQuery, and name it for example 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);
    

    So we have a simplest lib looks a like jQuery. Now we want add "plugin" to it, for example function square.

    As in jQuery we add this to prototype, or fn that same as prototype in our case:

    microM.fn.square = function() {
      return this.pow(2);
    }
    

    here we can call pow directly from this because in this case this instance of our microM, and all functions from microM.prototype is available directly;

    But when we call our map function that takes a callback inside callback this will be concrete element, for example Number primitive, because we call it like

    callback.call(this.context[i], this.context[i], i);
    

    where first param in call function - is thisArg.

    Possibly code snippet below can make clear my muddled explanation :-)

    (function(global) {
      var microM = function(context) {
        return new microM.fn.init(context);
      }
    
      microM.fn = microM.prototype = {
        version: '0.0.0.1',
        constructor: microM
      };
    
      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;
    
      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;
      }
    
      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) {
          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);
        }
      });
    
      global.microM = microM;
    })(window);
    
    
    microM.fn.printTo = function(id, descr) {
      document.getElementById(id).innerHTML += (descr ? descr + ": " : "") + JSON.stringify(this.get()) + '<br/>';
      return this;
    }
    
    microM.fn.square = function() {
      return this.pow(2);
    }
    
    var t = microM([2, 3, 4]).printTo('res', 'initial');
    t.square().printTo('res', 'square')
      .map(function(el) {
        return microM(this + 10).square();
      }).printTo('res', 'mapped')
      .map(function(el) {
        return this instanceof Number;
      }).printTo('res', 'inside map: this instanceof Number');
    <div id="res"></div>

    0 讨论(0)
提交回复
热议问题