I am fasinated by the jQuery library. I do so much more with so less code. Here I try to mimic jQuery several features: chain operation, extentsion, constructor.
chain operation is pretty easy to mimic. We just need to add "return this;" to the end of a method. Here is my first try
var jQuery = function() { } jQuery.prototype = { version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } var j = new jQuery(); j.showVersion().work();
Extension is also simple. We just need to decorate its prototype like this
var jQuery = function() { } jQuery.prototype = { version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } var j = new jQuery(); j.showVersion().work(); jQuery.prototype.sleep = function() { alert("sleep"); return this; } j.sleep();
The constructor is very tricky. First I need to create a jQuery object without "new" keyword. Can we just do this like the following?
var jQuery = function() { return jQuery.prototype; } jQuery.prototype = { version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } var j = new jQuery(); j.showVersion().work(); //chain works jQuery.prototype.sleep = function() { alert("sleep"); return this; } j.sleep(); //extension works j.version = "2.0"; j.showVersion(); jQuery().showVersion(); //we can create a jQuery object without new, but it show 2.0, it is a singleton.
It works. But seemly, there is a serious bug, that it returns a singleton. So I want to write the following naive code.
var jQuery = function() { return new jQuery.prototype; //jQuery.prototype is not a constructor //return new jQuery.prototype(); //jQuery.prototype is not a constructor }
It says, jQuery.prototype is not a constructor. so we need a constructor function to do the job.
var jQuery = function() { return new jQueryConstructor(); } jQuery.prototype = { version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } function jQueryConstructor() { }; jQueryConstructor.prototype = jQuery.prototype; //end of library //following is test code. var j = new jQuery(); j.showVersion().work(); //chain works jQuery.prototype.sleep = function() { alert("sleep"); return this; } j.sleep(); //extension works j.version = "2.0"; j.showVersion(); jQuery().showVersion(); //it shows 1.0, it is not a singleton
Now everything works. But what if user change the jQuery.prototype accidentally. let's add a reference jQuery.fn = jQuery.prototype, so that user focus on jQuery.fn, and let jQuery.prototype off attention. So I change the code like the following . Please note that the "return new jQueryConstructor()", you must use "new". Without "new", the prototype "jQueryConstructor.prototype = jQuery.fn" has no use. Here is an artical Create Advanced Web Applications With Object-Oriented Techniques more about the "new".
var jQuery = function() { return new jQueryConstructor(); } jQuery.fn = jQuery.prototype = { version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } function jQueryConstructor() { }; //jQueryConstructor.prototype = jQuery.prototype; jQueryConstructor.prototype = jQuery.fn; var j = new jQuery(); j.showVersion().work(); //chain works jQuery.fn.sleep = function() { alert("sleep"); return this; } j.sleep(); //extension works j.version = "2.0"; j.showVersion(); jQuery().showVersion(); //it shows 1.0, it is not a singleton
Can we make it more simple, yes, let's move the jQueryConstructor into the prototype.
var jQuery = function() { return new jQuery.fn.init(); } jQuery.fn = jQuery.prototype = { //nested init constructor inside //is just a hack init: function() {}, version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } //if we do not nested init inside //it would be init.prototype = jQuery.prototype jQuery.fn.init.prototype = jQuery.fn; var j = new jQuery(); j.showVersion().work(); //chain works jQuery.fn.sleep = function() { alert("sleep"); return this; } j.sleep(); //extension works j.version = "2.0"; j.showVersion(); jQuery().showVersion(); //it shows 1.0, it is not a singleton
Done. I have skeleton of jQuery.
No comments:
Post a Comment