When I first started writing my own code I never understand jQuery's 'enhanced' init constructor until later on so I stuck to a different way of constructing my objects. I was wondering if I should keep my old ways or start using my own 'enhanced' init constructor.
My Constructor:
var $ = function(selector,context,createObj) {
if(createObj) {
// actually initiating object
} else {
return new $(selector,context,true);
}
};
jQuery:
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
};
Actual Init:
init: function( selector, context, rootjQuery ) {
// some code
}
Changing prototype (jQuery.prototype.init.prototype=jQuery.prototype):
jQuery.fn.init.prototype = jQuery.fn;
jQuery's constructor pattern is historically grown and bad practise - or at least unnecessarily complicated. If you want a constructor that works well without new (if applied wrong), use
function $(selector, context) {
if (this instanceof $) {
// actually initiating object
} else {
return new $(selector, context);
}
}
Related
I am trying to return a query like object, in my first try I try the Object.create method
var ElementArray = {
someMethod : myMethod,
....
}
var addMethods = function(elements) {
var obj = Object.create(ElementArray);
obj[0] = elements;
return obj;
};
var getId = function( query ) {
return addMethods( doc.getElementById(query) );
};
(jsperf)
I immediately found that this was slower then jQuery(sizzle), especially on firefox. The issues with firefox where probably to do with cross-compartment wrappers (see bug here), but I was still quite dissatisfied.
I also tried using prototype instead
var ElementArray = function(){};
ElementArray.prototype.someMethod = someMethod;
....
var addMethods = function(elements) {
var obj = new ElementArray();
....
};
Slightly better on Chome, but still very slow on firefox.
So my question is, how does jQuery(sizzle), and other libraries do it || Whats the fastest way to return a object with a 1-2 instance properties? (Everything else can just be references)
So my question is, how does jQuery(sizzle), and other libraries do it
jQuery uses the prototype. It kind of hides that fact by aliasing the prototype to .fn, but it is still the prototype. Here's the jQuery function.
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
},
And, here's the aliasing:
jQuery.fn = jQuery.prototype
And, the implementation of the actual jQuery constructor:
init = jQuery.fn.init = function( selector, context, root ) {
var match, elem;
// HANDLE: $(""), $(null), $(undefined), $(false)
if ( !selector ) {
return this;
}
// Method init() accepts an alternate rootjQuery
// so migrate can support jQuery.sub (gh-2101)
root = root || rootjQuery;
.....
And, the round-about assignment of the `.init.prototype':
// Give the init function the jQuery prototype for later instantiation
init.prototype = jQuery.fn;
I'm trying to create a jQuery like architecture in my app but i could not get my expected results.
In jQuery "The jQuery object is actually just the init constructor 'enhanced'".
jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
},
That means when you initiate the jQuery object with;
$('selector')
jQuery returns the
new jQuery.fn.init( selector, context, rootjQuery );
jQuery prototype is defines as;
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;
...
return jQuery.makeArray( selector, this ); // An array
}
...
size: function() {
return this.length;
},
...
all the usefull properties and methods of jQuery (like hide(), show() exct.) are hold by prototype of the jQuery object.
And the prototype of the init method assigns as the prototype of the jQuery;
jQuery.fn.init.prototype = jQuery.fn;
Well!. My problem is I tried to use this architecture but I could not get the properties and methods of the returned value.
Here is my code;
(function() {
Metinler = function(MetinKodu){
return new Metinler.sub.baslat( MetinKodu );
}
Metinler.sub = Metinler.prototype = {
metinKodlari: [],
constructor: Metinler,
topla: function(){
return this.metinKodlari[0] + this.metinKodlari[1];
},
baslat: function(MetinKodu) {
if($.isArray(MetinKodu) && MetinKodu.length > 0) {
this.metinKodlari = MetinKodu;
}else{
this.metinKodlari = (MetinKodu) ? [MetinKodu] : [''];
}
return this.metinKodlari;
}
}
Metinler.sub.baslat.prototype = Metinler.sub;
window.Metinler = Metinler;
})()
Code
The problem you are seeing, is that your constructor is returning a specific value:
return this.metinKodlari;
... which returns your internal array (well, you array of an array).
Remove this line and you'll return your baslat instance.
Your baslat function is faulty:
You misspelled length in MetinKodu.lenght > 0.
You're returning the metinKodlari array, whereas you should return the newly created this context. jQuery uses makeArray on this to store the passed DOM elements in the array-like jQuery object. In your case however, you simply want to store the passed elements in the metinKodlari array instead of on the this object itself.
This should work:
baslat: function(MetinKodu) {
if ($.isArray(MetinKodu) && MetinKodu.length > 0) {
this.metinKodlari = MetinKodu;
} else {
this.metinKodlari = (MetinKodu) ? [MetinKodu] : [''];
}
return this;
}
I admit this question is getting to the limits of what I know of JavaScript & jQuery, and there is probably a more proper way to state my question (which would help in finding an existing solution), but if you can bear with me, this is what I'm after.
I have an existing object class I've defined. I'm making a jQuery ajax call using getJSON, and I want my callback parameter (which is an object) to be classed as my custom object, so that I can access that class' methods from it.
So I have some object class
function Boo() {
this.param1;
this.param2;
this.yah = function() {
...
}
}
and then I have something elsewhere of the sort
$.getJSON(url,function(new_instance) {
//from my php source this passed object is already loaded with param1, param2...
alert(new_instance.param1); //no probs
//but i want to be able to then call
new_instance.yah();
});
In other words, I want new_instance to be considered an instance of Boo(). I know in stuff like ActionScript you have to class the incoming parameters for exactly this reason, dunno what flexibility I have in JS.
I thought maybe about having an intermediate function that takes in the incoming object and creates/populates a new instance of Boo() but not sure if there is a more clever method.
Many thanks!!
Do not define methods in the constructor function, you are
defining them over and over again every time the costructor
is called. Move them over to the prototype:
Boo.prototype = {
yah: function() {
},
bah: function() {
}
...
};
a little helper function:
function coerceTo( proto, values ) {
var r = Object.create( proto );
for( var key in values ) {
r[key] = values[key];
}
return r;
}
Depending on browser, Object.create might not be available, so:
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw new Error('Object.create implementation only accepts the first parameter.');
}
function F() {}
F.prototype = o;
return new F();
};
}
Usage:
new_instance = coerceTo( Boo.prototype, new_instance );
new_instance instanceof Boo //true
new_instance.yah();
What you can do:
$.getJSON(url,function(newObjData) {
var newObj = $.extend(new Boo(), newObjData);
newObj.yah();
});
Also consider moving your Boo methods to object prototype so the methods don't get recreated for each Boo instance:
var Boo = function() {
this.param1;
this.param2;
}
Boo.prototype.yah = function() {
console.log(this.param1);
}
I'm struggling with how best to combine javascript Classes and jQuery plugins. This question isn't very specific, what I'm hoping for is pointers to more resources.
Basically, I want to store state data and private methods in a class, and then extend each jQuery object which I call my plugin on to have those private methods and properties. Such that inside the plugin I can call methods directly off the jQuery object.
I read jQuery plugin design pattern (common practice?) for dealing with private functions, specifically David's answer, however this initializes a new Class each time, and thus can't be used to save the state of the object.
I also found http://fuelyourcoding.com/jquery-plugin-design-patterns-part-i/, which recommends creating a class and then storing it in .data().
I think ideally what I want to end up with is code that looks like
(function( $ ){
var methods = {
init : function( options ) { // Initialize each object with a state and private methods },
show : function( ) {
// testFoo() is a private method that checks the element's state
if(this.testFoo()){
// Relying on jQuery's html() method
this.html() = this.fooTemplate();
}
}
};
// Boiler plate plugin from http://docs.jquery.com/Plugins/Authoring
$.fn.myPlugin = function( method ) {
// Method calling logic
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.myPlugin' );
}
};
})( jQuery );
Finally, it doesn't seem like I can bake the private methods into the plugin directly because methods like "testFoo()" will return a boolean, and therefore aren't chainable.
Thoughts? Am I approaching this the right way? Is there another design pattern I should be using? Perhaps not using jQuery plugin architecture at all?
Here's a proposed solution. It combines few different approaches (John Resig's inheritance model and Alex Saxton's plugin inheritance model).
Define your inheritable plugin:
(function ($) {
My.Plugin = Class.extend({
/*
* Initialization (constructor)
*/
init: function (element, meta) {
var $meta = $.extend({ name: "pluginName" }, meta);
// Call the base constructor
this._super(element, $meta);
// TODO: Add custom initialization code like the following:
// this._testButton = $('.testButton', element).get(0);
},
/*
* Public methods
*/
show: function() {
alert('This is a public method');
},
/*
* Private methods
*/
// DEMO: Overriding the base _paint method:
_paint: function () {
// "this._super()" is available in all overridden methods
// and refers to the base method.
this._super();
alert('TODO: implement myPlugin._paint!');
}
});
// Declare this class as a jQuery plugin
$.plugin('my_plugin', My.Plugin);
})(jQuery);
Define Base class
(function () {
var initializing = false, fnTest = /xyz/.test(function () { xyz; }) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function () { };
// Create a new Class that inherits from this class
Class.extend = function (prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] =
typeof prop[name] == "function"
&& typeof _super[name] == "function"
&& fnTest.test(prop[name])
? (function (name, fn) {
return function () {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name])
: prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if (!initializing && this.init)
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
Plugin Creation
(function ($) {
// The "inheritance plugin" model
// [http://alexsexton.com/?p=51][1]
$.plugin = function (name, object) {
$.fn[name] = function (options) {
var instance = $.data(this, name, new object(this, options));
return instance;
};
};
})(jQuery);
Calling your plugin from javascript:
$('#someElem').my_plugin({options: {}, data: {} /* you can modify your plugin code to accept anything */}).show();
Note:
Private methods here are marked as _methodName. It's pure convention. If you really want to hide them, you can use module pattern (google for it or here's one for starters: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth)
Is this what you're looking for?
sometimes we loss the new keyword when define new object,
obj = new Clazz(); //correct
obj = Clazz(); //wrong, but no syntax error, hard to debug.
I want to write a function to help me create Class and make it new safe.
var Class = function(){
var constructor = arguments[0];
var superClasses = arguments[1..n];
function clazz(){
if(! this instanceof clazz){
return new clazz()//pass clazz arguments,not Class arguments
}
constructor();//pass clazz arguments
}
//clazz inherit from superClasses
return clazz;
}
var MyClazz = Class(function(name){
this.name = name
}, SuperClazz1, SuperClass2 )
MyClazz.extend({
show: function(){console.log(this.name)}
})
obj1 = new MyClazz("name1");
obj2 = MyClazz("name2");
// obj1 should same as obj2
Is it possible, any exists module?
sometimes we loss the new keyword...
All about coding discipline and testing... anyways, moving on to your question.
To find out whether your function was called as a constructor use instanceof:
function Foo() {
console.log(this instanceof Foo);
}
Foo(); // false
new Foo(); // true
When calling a function as a constructor this refers to the newly created object, otherwise this refers to the object the function was called on, in case it wasn't called on anything this will refer to the global object.
Update
Passing variable arguments to a constructor is not possible. new clas.call(....) will yield an error that call is not an constructor.
You can do two things:
Instead of returning the Class function itself from your class factory method, return a function that creates a new instance, sets up all the needed stuff and then returns that instance (this will make inheritance waaaay more complicated)
Just use the new keyword.
I've written my own Class thingy, and I've tried to support both new and () syntax for creating instances. The whole inheritance stuff etc. is complicated enough, making it even more magic just to save 4 more characters... not worth the effort. Use new and write tests.
Another Update
OK I couldn't resist to hack around more and I made it work:
function is(type, obj) {
return Object.prototype.toString.call(obj).slice(8, -1) === type;
}
function clas(args) {
if (is('Object', this)) {
ctor.apply(this, is('Arguments', args) ? args : arguments);
} else {
return new clas(arguments);
}
}
This will do the magic, at least in my case.
Sorry for the late submission on this answer but I believe it directly answers your question. My solution is to check the type of the constructed object and act accordingly.
You can see my solution here:
http://mikepackdev.com/blog_posts/9-new-scope-safe-constructors-in-oo-javascript
I hope this helps!