JavaScript init function and its use - javascript

I'm new to JavaScript and saw a coode where a init function is used while declaring the object..I tried searching for "JavaScript init functions" but it does not take me to any correct document. Also, it does not provide me the exact application of this function…
I have modelled a function on how it looks like
var1 = Class.extend({
init : function(){ alert ('Hi'}
}
Question:
How does init does called? Is it similar to the init(initialization) method in Object oriented concepts.
Can you please provide a example on how init function could be called?

init is a custom function name, it may be called by the framework or by the object constructor and usually keeps place of a post construction method. For instance I declare it for jQuery plugins, like this:
;(function($, window, document, undefined) {
// Create the defaults once
var pluginName = "Display", defaults = {
cols : 32,
rows : 16
};
// The actual plugin constructor
function Display(element, options) {
// Object variables
this.options = $.extend({}, defaults, options);
this.size = {};
// Post construct
this.init();
}
// methods of the Display
display.prototype = {
init : function() {
this.setSize(this.options.rows, this.options.cols);
},
setSize : function(rows, cols) {
// calculates size
}
};
// JQuery Plugin declaration
// ...
})(jQuery, window, document);
With this, a call (from the correct scope) to new Display() will call the init method.

Init in most framework is used to be called after the object initialization. It is called automaticaly so you just put in the code you want to execute after the object is initialized. It is similar to constructor however it is not the same. For an example in backbone which is cool javascript framework (you see this init functions only in frameworks it is not native javascript method)
Constructor runs before Backbone sets up the structure. initialize is called inside the structure's constructor function. So basically if you need to augment anything before Backbone sets up the structure, use constructor if you need to augment anything after Backbone sets up the structure use initialize.

Related

Vanilla JS “plugin” structure

I wrote a JS "plugin" using the following clever structure (which was not an idea of mine, I found googling around).
It basically functions as a class, with private methods, but don't have to use the private keyword notation (which is not fully supported even in modern browsers), or the class notation.
var myPlugin = (function () {
'use strict';
/**/
var Constructor = function (options) {
var publicAPIs = {};
//private method
function myFunction() { }
//public method
publicAPIs.myFunction2 = function () {
return 1;
}
return publicAPIs;
};
return Constructor;
})();
Now the problem is I don't fully get how this works.
It is used in the following way :
var myPlugin = new myPlugin({
selector: '#selector-test'
});
myPlugin.myFunction2();
I guess the "new" keyword will use the outer function which returns the Constructor (which returns the publicApi object). Is that correct ?
Also, I guess instantiating an Object in this way will "copy" all the Constructor's functions within each instantiated Object (which is not a problem in my case, since I'm using just a single Object).
Another question I have is the following :
Would it be possible in JS to call this plugin directly on an element instead of passing the selector (or directly the element) in the arguments ? Basically something like JQuery plugins work. I'd like to do something like the following :
var myElement = document.querySelector('#id');
myElement.myPlugin(options);
Thanks.

Way to extend Marionette.js view classes

I need to extend marionette.js classes with some functionality I'd like to have in all classes I create in my app.
What I currently do is to save original method of Marionette and to override it with my own method, calling to original from inside overridden.
For instance:
(function() {
var oldMarionetteItemViewConstructor = Marionette.ItemView.prototype.constructor;
Marionette.ItemView.prototype.constructor = function() {
// Some custom stuff I want to have here
.....
// Call to original constructor
return oldMarionetteItemViewConstructor.call(this, arguments);
}
})();
It seems some hacky and I wonder if there better way?
Marionette hoists the Backbone.View.extend() method (which itself is actually hoisted from Underscore.js) so all you have to do is:
var MyFancyView = Marionette.ItemView.extend({
//define your custom stuff here
});
var MyExtendedView = MyFancyView.extend({
//This view picks up the same props/methods form MyFancyView
});
You're pattern works, but the native #extend() method will keep your prototypes clean:
https://github.com/jashkenas/underscore/blob/master/underscore.js#L838

Extend $fn namespace in jQuery

This seems simple but I cannot figure how to extend the $fn namespace.
JS:
(function ($) {
$.fn.myorg.level1.level2.myFunction = function (usettings, params) {
return this.each(function () {
//do work...etc
});
};
} (jQuery));
$("bla").myorg.level1.level2.myFunction(...);
How do I define the namespace chain so I can write functions like above?
The example I have given is very simple, the namespace isn't expected to be very deep however, I need to be able to extend and add functions...etc to my namespace tree at will. I don't want to redefine the tree for each addtional function/level I add.
I haven't seen any good examples. If I stay at the $fn level it's easy, but that doesn't make my code as clean and extensible as I need it.
If what I am asking for is not possible, what is the correct approach?
Epascarello hinted at this, but I'm guessing that the previous objects aren't defined.
console.log($.fn.myorg); // undefined
$.fn.myorg.level1 = function(){}; // TypeError: Cannot set property 'level1' of undefined
But if we define things first:
$.fn.myorg = $.fn.myorg || {}; // if this object doesn't exist, create an blank object
console.log($.fn.myorg); // object
$.fn.myorg.level1 = function(){};
console.log($.fn.myorg.level1); // function

jQuery Plugin - Providing an API

I am currently developing a rather complex jQuery plugin. One that I am designing to be extensible. The quandary I have is how to exactly provide my users with the APIs available to them.
There are two methods that I can come up with:
Provide the API via an object in the global scope
This is the method I am currently using. I do it similar to this:
(function ($, win, undefined) {
//main plugin functionality
function pluginStuff() { /*...including method calling logic...*/ }
//register function with jQuery
$.fn.extend({ Plugin: pluginStuff });
//register global API variable
win.PluginAPI = { extendMe: {}, getVar: function() {} };
})(jQuery, window);
Unfortunately since I impliment the standard $().plugin('method') architecture its a little strange to have to use the jQuery method for some things and the API variable for others.
Provide the API via an object placed in jQuery
I toyed with this method as well but its best practice to take up only a single slot in jQueries fn scope, as not to crowd the jQuery variable. In this method I would put my api variable in $.fn instead of the window:
//register function with jQuery
$.fn.extend({ Plugin: pluginStuff });
//register global API variable
$.fn.PluginAPI = { extendMe: {}, getVar: function() {} };
I would rather not break this convention and take up two places.
Now that I write this I can see a third option where I assign my plugins slot in jQuery's fn scope to be an object:
$.fn.Plugin = { plugin: pluginStuff, api: { extendMe: {}, getVar: function() {} } };
but how well received would this be if users had to do $('#elm').Plugin.plugin({ setting: 'value' }) to create a new instance of the plugin?
Any help or pointers would be greatly appreciated.
Please Note: I'm am not looking for a way to incorporate the API object into my plugin functionality. I am looking for a way to keep it separately modularized, but intuitively available for use/extension.
You could always do like
var plugin = function plugin() { /* do the main stuff */ };
// api stuff here
plugin.getVar = function() { };
plugin.extendMe = {};
$.fn.Plugin = plugin;
Or stick the extra stuff in an object that you assign to plugin.api.
Any way you do it, though, you're going to have to worry a bit about settings bleeding into each other. Since everything's going to be using the same function, regardless of how you choose to set it up, you'll need a way to keep invocations of the plugin separate from one another. Perhaps using something like, say, this.selector (in your plugin function) as a key into an associative array of properties, for example. I'd normally recommend .data() to attach settings to individual elements, but that doesn't help much if the same element gets the plugin called for it twice.
The method I eventually decided to use was registering the plugin under the fn namespace and the api variable under the jQuery $ namespace. Since methods and options set operate on an instance of the plugin $.fn is the best choice.
However, the API is global and does not link to a single instance. In this case $.fn doesn't quite fit. What I ended up using was something similar to this:
(function ($, win, undefined) {
//main plugin functionality
function pluginStuff() { /*...including method calling logic...*/ }
//register function with jQuery
$.fn.Plugin = pluginStuff;
//register global API variable
$.Plugin = { extendMe: {}, getVar: function() {} };
})(jQuery, window);
now you can create an use a plugin object as expected:
$('#elm').Plugin();
$('#elm').Plugin('option', 'something', 'value');
$('#elm').Plugin('method');
and you can easily extend and access the API:
$.extend($.Plugin.extendMe, {
moreStuff: {}
});
$.Plugin.getVar('var');
Thanks for the help everyone!

Javascript object properties access functions in parent constructor?

So I'm using this pretty standard jquery plugin pattern whereby you can grab an api after applying the jquery function to a specific instance.
This API is essentially a javascript object with a bunch of methods and data.
So I wanted to essentially create some private internal methods for the object only to manipulate data etc, which just doesn't need to be available as part of the API.
So I tried this:
// API returned with new $.TranslationUI(options, container)
$.TranslationUI = function (options, container) {
// private function?
function monkey(){
console.log("blah blah blah");
}
// extend the default settings with the options object passed
this.settings = $.extend({},$.TranslationUI.defaultSettings,options);
// set a reference for the container dom element
this.container = container;
// call the init function
this.init();
};
The problem I'm running into is that init can't call that function "monkey". I'm not understanding the explanation behind why it can't. Is it because init is a prototype method?($.TranslationUI's prototype is extended with a bunch of methods including init elsewhere in the code)
$.extend($.TranslationUI, {
prototype: {
init : function(){
// doesn't work
monkey();
// editing flag
this.editing = false;
// init event delegates here for
// languagepicker
$(this.settings.languageSelector, this.container).bind("click", {self: this}, this.selectLanguage);
}
}
});
Any explanations would be helpful. Would love other thoughts on creating private methods with this model too.
These particular functions don't HAVE to be in prototype, and I don't NEED private methods protected from being used externally, but I want to know how should I have that requirement in the future.
// Edited based on Matthew's comment
So I tried moving the prototype definition based on Matthew's comment. This seems to work now, but still not sure if this is the correct way to be doing this. Thoughts? Obviously it would be cleaner if I move the prototype object into a separate area
$.TranslationUI = function (options, container) {
function monkey(){
console.log("blah blah blah");
}
// extend the default settings with the options object passed
this.settings = $.extend({},$.TranslationUI.defaultSettings,options);
// set a reference for the container dom element
this.container = container;
$.extend($.TranslationUI.prototype,
{
init : function(){
monkey();
// editing flag
this.editing = false;
// init event delegates here for
// languagepicker
$(this.settings.languageSelector, this.container).bind("click", {self: this}, this.selectLanguage);
}
}
);
// call the init function
this.init();
};
So while this works, the crappy part is that I'm re-initing prototype every time that constructor runs. I'm sure that's not efficient. But not sure how else to have the prototype methods have access to private functions/variables of a certain instance.
The error is because monkey is not defined in the scope you're calling $.extend from.
Alright. So found an answer on stackoverflow, confirmed by Crockford's site.
javascript - accessing private member variables from prototype-defined functions
Essentially, you can't really get access to private functions from the prototype methods. You can via 'privileged' functions, which in turn call private variables and functions, but then you are basically creating a crapload of getters and setters, which might just be doubled in your prototype "public" methods.
So its kind of a lot of work, especially if your stuff doesn't TRULY need to be private.
Have a look at my answer and some of the others here:
call function inside a nested jquery plugin

Categories

Resources