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
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
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>