This question already has answers here:
How can I merge properties of two JavaScript objects dynamically?
(69 answers)
Closed 9 years ago.
I have 2 BI object in different files, now I want to extend the first object with other ones.
1st Object
var BI = BI || {};
BI = {
firstInit: function () {
console.log('I am first init');
}
}
Other file
2nd Object
BI = {
init: function () {
console.log('I am init');
}
}
Now I want 2nd Object should contain the firstInit as well. Let me know I can explain further. I am using jQuery.
You can use jQuery's $.extend here.
Try following code
var BI = BI || {};
BI = {
firstInit: function () {
console.log('I am first init');
}
}
$.extend(BI, {
init: function () {
console.log('I am init');
}
});
console.log(BI);
Here is the DEMO
Out of the box, you can't do it that easily with good x-browser support.
However, jQuery does give you a means to have objects extend eachother: http://api.jquery.com/jQuery.extend/
So you would do:
var extended = $.extend({}, BI, {
init: function () {
console.log('I am init');
}
});
The first argument (empty object, {}) means that the properties of BI (the second argument) and the object you pass in will be combined in to the new object.
I wrote a small polymorphic extension to $.extend for this purpose which will allow you to extend from multiple objects, with the latter item taking precidence:
mergeObjects = function () {
// Convert the arguments Array-like object to an actual array
var args = Array.prototype.slice.call(arguments);
// Only one item? If we give this to $.extend it'll extend jQuery, which is
// not the desired result, so let's spit it back verbatim
if (args.length === 1) {
return args[0];
}
// We need to make sure we're always combining objects starting with a
// completely empty one
args.unshift(true, {});
return jQuery.extend.apply(jQuery, args);
};
So, you can define your base module with common properties like so:
var MyBaseModule.prototype = {
options: {},
getOptions: function () {
return this.options || {};
},
setOptions: function (options) {
this.options = options;
},
log: function () {
// do your logging stuff here
},
error: function () {
// do your error handling stuff here
}
};
And your actual modules:
var MyModule = function () {
// constructor code here
};
var MyModule.prototype = mergeObjects(MyBaseModule, {
// define your module's methods here
});
...now MyModule has "inherited" the options property and options getter and setter. You can instantiate the new module with new MyModule;
If you want a vanilla way of doing it, this post may be useful
There are 2 ways of doing this in JavaScript. One is using prototype chaining, the other is to just copy the method. In this case both of your objects have the object as the prototype, so you need to copy the method:
BI2.init = BI1.firstInit;
To copy all methods and attributes in JQuery, use $.extend;
BI2 = $.extend({ init: function () { } }, BI1);
In Javascript Functions are objects. So they can be passed as arguments to functions or assigned to other variables (referenced).
var BI = {
firstInit: function () {
console.log('I am first init');
}
};
var BI2 = {
init: function () {
console.log('I am init');
}
}
// copy the reference of function
BI2.originalFirstInit = BI.firstInit;
// run this function
BI2.originalFirstInit(); // output: "I am first init"
Related
I have my javascript code as follow:
$(document).ready(function () {
//call of global functions
globalFunction1();
globalFunction2(); //create a new object inside
globalFunction3();
}
function globalFunction1() {
// do something directly with jquery selectors
var testObj1 = new object1($('#tree')); // this is called later in the function
testObj.doSomething();
}
function globalFunction2() {
// do other things
}
function globalFunction3() {
// do something directly with jquery selectors
}
//creating an object in js
var object1 = (function () {
var tree;
function object1($tree) {
tree = $tree;
});
}
object1.prototype.doSomething = function () {
.....
};
return fancyStructure;
})();
Normally I have more global functions and if possible I always try to create objects using the new keyword (as in Java or C#)
Now, I am asked to provide namespacing in order to avoid function conflict problems. Thing is I am not sure how to achieve that giving my current code and knowing that I need to keep the code Object Oriented.
Hence, I am wondering if there is a way to add some namespacing effisciently. Any suggestion will do as long as it is along the lines of adding a namespace.
Just put your functions into an Object:
var mynamespace = {
globalFunction1 : function() {
// do something directly with jquery selectors
var testObj1 = new object1($('#tree')); // this is called later in the function
testObj.doSomething();
},
globalFunction2 : function() {
// do other things
},
globalFunction3 : function() {
// do something directly with jquery selectors
}
}
and call the functions with
mynamespace.globalFunction1();
Or you could just define your namespace
mynamespace = {};
And later add the the functions with
mynamespace.globalFunction1 = function() {
//do something
};
Use objects as containers for your functions. This is the standard approach of code structuring in JS.
var namespace1 = {
func1: function() {},
func2: function() {},
}
var namespace2 = {
func1: function() {},
func2: function() {},
}
namespace1.func2();
You can store your OOP code in this namespaces:
var namespace3 = {
someObj: function() {},
create: function() { return new this.someObj(); },
}
namespace3.someObj.prototype = {
count: 15,
someFunc() {}
}
And you can easily extend them:
namespace3.anotherObj = function () {}
Edit
Regarding your example:
var fancyStructureWrapped = (function () {
var tree;
function fancyStructure($tree) {
tree = $tree;
});
fancyStructure.prototype.doSomething = function () {
.....
};
return fancyStructure;
})();
// add it to some namespace
someNamespace.fancyStructure = fancyStructureWrapped;
//create an instance
var fs = new someNamespace.fancyStructure();
//and use it
fs.doSomething();
If you're looking for a general approach to managing a growing JavaScript codebase, check out RequireJS and/or Browserify. Both are libraries that allow dividing your code up into modular bits (ie. AMD or CommonJS modules) and then referencing/importing between them. They include tooling for bundling these files into a single JS file when it's time to deploy a production build too.
I’ve been using the Javascript Revealing Module pattern a lot and I like the clear separation it gives between the public interface and the internals. However I keep running into a situation which makes me wonder if my overall usage pattern is correct, or if I should use some variant of the pattern.
The problem is when something passed into the init function of a module and stored privately for internal use also needs to be publicly exposed, either in a Knockout binding expression or some other module. The return statement of the module executes immediately and sometime later the init function is called, typically being passed some dynamic parameters such as Ajax URLs or raw JSON rendered in a script block within a Razor view. Because the module's return statement just returns a copy of the private variable rather than a reference, my setting that private variable in the init function can’t change what has already been returned.
var productsModule = function() {
var urls;
var init = function(ajaxUrls) {
urls = ajaxUrls;
};
return {
init: init,
urls: urls,
getUrls: function() { return urls; }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls); // undefined
alert(productsModule.getUrls()); // object
} ;
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
My workaround is just to wrap objects such as “urls” in a function and then access them via productsModule.getUrls(). However that becomes very messy, especially if the variable is a Knockout observable which is itself a function, and hence to evaluate it I need to use double brackets like productsModule.getMyObservable()().
Is there a nicer way to get at the up-to-date internal values using something which at least approximates the revealing module pattern?
Basic types are passed by value while objects are passed by reference; you could exploit this so that instead over overwriting urls in productsModule you just update it. This way the reference returned in the initial module invocation remains up to date. I've updated your code to show what I mean.
var productsModule = function() {
var urls = {};
var init = function(ajaxUrls) {
// Merge properties into the original object instead; more robust approach
// may be needed
for ( name in ajaxUrls ) {
if (ajaxUrls.hasOwnProperty(name)) {
urls[name] = ajaxUrls[name];
}
}
};
return {
init: init,
urls: urls,
getUrls: function() { return urls; }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls); // undefined
alert(productsModule.getUrls()); // object
} ;
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
Although I don't completely like the idea of having to iterate through all the possible levels of my objects to merge them like that, El Yobo's answer got me thinking about making the result of the module function itself a local variable whose properties I could update.
var productsModule = function() {
var urls;
var init = function(ajaxUrls) {
urls = ajaxUrls;
result.urls = urls;
};
var result = {
init: init,
urls: urls
};
return result;
}();
// Before init
alert(productsModule.urls); // undefined
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
alert(productsModule.urls.getProduct); // /Product/
Why don't you make urls an observable property ?
Look at my example:
http://jsfiddle.net/Razaz/zkXYC/1/
var productsModule = function() {
var urls=ko.observable();
var init = function(ajaxUrls) {
urls(ajaxUrls);
};
return {
init: init,
urls: urls,
getUrls: function() { return urls(); }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls()); // undefined
alert(productsModule.getUrls()); // object
};
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
Greetings.
I'm working on a file manager framework similar to elFinder. My current code works fine but now I want to make it look better and add chaining (I'm not sure if it's chaining or decorator pattern).
Here is a sample of what I want to do:
function UI() {}
UI.prototype.folders = function(){
return [];
}
UI.prototype.folders.prototype.getSelectedFolder = function(){
return {};
}
Calling UI.folders() should return an array of folder objects. So if you call UI.folders() you would get something similar to this:
[
Object { name="folder1", selected=false },
Object { name="folder2", selected=false },
Object { name="folder3", selected=true }
]
And calling UI.folders().getSelectedFolder() would filter the results from UI.folders() and will return:
Object { name="folder3", selected=true }
Is this possible? Is it right to say "chaining" in this case or it's "decorative pattern"?
If it's not - is there another more appropriate way to do it?
Any help wold be really appreciated!
The code in your question isn't reflective of a proper implementation, but to answer your direct questions, yes, this...
UI.folders().getSelectedFolder()
...would be an example of method chaining.
A decorator pattern is different. If you have a set of methods, and each one should always first invoke some common function, you can create a decorator that will return a function that first calls the common one, then the actual one...
function foo() {
console.log('I\'m foo, and I\'m first, and I was given these args:', arguments);
}
function decorateWithFoo(decorated) {
return function () {
foo.apply(this, arguments);
decorated.apply(this, arguments);
};
}
So you can use decorateWithFoo to create a function that always invokes foo first...
// create and decorate bar()
var bar = function(a,b) {
console.log('I\'m bar, and I was called after "foo", and was given args:', a, b);
};
bar = decorateWithFoo(bar);
bar(123, 456); // this will first call `foo()`, then (the original) `bar()`.
// create and decorate baz()
var baz = function(a,b) {
console.log('I\'m baz, and I was called after "foo", and was given args:', a, b);
};
baz = decorateWithFoo(baz);
baz(123, 456); // this will first call `foo()`, then (the original) `baz()`.
Some languages have built in syntax for creating decorators. JavaScript currently does not.
If you find yourself using decorators in different ways, you could create another function that sets up the initial decorator function...
function generateDecorator(decorator) {
return function (decorated) {
return function () {
decorator.apply(this, arguments);
decorated.apply(this, arguments);
};
};
}
So our original decoreateWithFoo could have been set up like this...
function foo() {
console.log('I\'m foo, and I\'m first, and I was given these args:', arguments);
}
var decorateWithFoo = generateDecorator(foo);
To make this work properly, you need to make your folders method be a function that returns an object that inherits from an array.:
UI.prototype.folders = function(){
// must return an object that inherits from an array
// that has the additional methods on it you want like getSelectedFolder()
}
The are a few different ways to solve this. The primary goal is that when you call a function you get an object/function back that is the same type of object with different properties. I'm not a fan of the prototype usage so I would do it like this (this is one way to solve it):
var FolderList = function ()
{
var _folders = [];
folders.pop({ name: "folder1", selected: false });
folders.pop({ name: "folder2", selected: true });
folders.pop({ name: "folder3", selected: false });
// prevent other programers from changing _folders
// which would break this, so just use a function
this.folders = function ()
{
return _folders;
}
this.selectedFolders = function ()
{
var tmpFolders = [];
for (var folderIndex = 0;
folderIndex < this._folders.length;
folderIndex++)
{
if (this._folders[folderIndex].selected)
{
tmpFolders.pop(_folders[folderIndex]);
}
}
_folders = tmpFolders;
return this;
}
this.addFolder = function (folder)
{
_folders.pop(folder);
return this;
}
};
var folderList = new FolderList();
folderList.selectedFolders()
.addFolder({ name: "folder1", selected: false })
.addFolder({ name: "folder3", selected: true })
.selectedFolders();
// array of 2 objects, folder2 and folder3
var arrayOfSelectedFolder = folderList.folders();
Ok this may be a noobolicious question as im new to OOP.
Im attempting to build something of a JS Object Library and was wondering if I could do it using nested functions??
var object = new function() {
this.action1 = function () {
this.dostuff1 = function () {
return "dostuff1";
};
this.dostuff2 = function () {
return "dostuff2";
};
};
I am having trouble accessing the third level functions. Can I nest like this?
this.action2 = function () {
return "action2";
};
alert(object.action1.dostuff2());
While Eberlin's answer is perfectly correct I'd suggest you to create a nested object which in turn again exposes functions rather than nesting functions itself. Otherwise this might become a maintainability nightmare.
Basically you could create
var Child = function(){
//constructor
};
Child.prototype.doStuff2 = function(){
return "dostuff2";
};
var Root = function(obj){
//constructor
this.child = obj;
};
Root.prototype.action1 = function(){
return "doStuff1";
};
//usage
var myRoot = new Root(new Child());
myRoot.action1();
myRoot.child.action2();
Here's a live example: http://jsbin.com/ijotup/edit#javascript,live
See below for some code cleanup:
var o = (new function () { // changed 'object' to 'o'
this.action1 = (function () { // added parentheses, not required.
this.dostuff1 = (function () { // does not return anything.
return "dostuff1"; // and is also not the proper way to organize
}); // ** look at the javascript prototype
return this; // now it does
}); // missing closing bracket
this.dostuff2 = (function () {
return "dostuff2";
});
});
alert(o.action1().dostuff2()); // action1 is a function, not a variable.
Hope this helps. Also, here's a brief tutorial on the javascript prototype.
I have this code:
var myWidget = $('#myWidget');
and calls like this elsewhere:
myWidget.hide();
myWidget.slideToggle();
These work of course because jQuery adds these methods.
Now, let's say I'm doing some refactoring to make myWidget a proper object with its own custom methods and state:
var myWidget = (function() {
// private stuff
var actualJQueryObject = $('#myWidget');
return {
publicMethod: function() {...},
// MAGIC!
}
})()
but I want to have all the calls that expect a jQuery object, which are all around my code, to still work even though myWidget is no longer a jQuery object, because myWidget knows how to delegate these calls to actualJQueryObject.
Is this possible?
You could also extend your jQuery object, with another object that has your custom methods:
var myWidget = function() {
// private stuff
var actualJQueryObject = $('#myWidget');
var extensionMethods = {
publicMethod: function() { alert('public method!'); }
}
return $.extend(actualJQueryObject, extensionMethods);
}();
Just be careful with the name of your extension methods, to not clash with any other jQuery defined function.
You can try the above snippet here.
One option is using the original jquery object as a prototype.
function wrap(jqObject) {
function MyNewType() {
this.changeFontSize = function(a) {
this.css({fontSize : this.size});
};
}
MyNewType.prototype = jqObject;
return new MyNewType;
}
var obj = wrap($('#someitem'));
obj.size = 50; // obj.size
obj.changeFontSize(); // obj.changeFontSize
obj.hide(); // $.hide
obj.fadeIn("slow"); // $.fadeIn
I've written a plugin that might help you. It's basically a plugin for writing plugins. This dev group post explains it and has some code samples:
http://groups.google.com/group/jquery-dev/browse_thread/thread/664cb89b43ccb92c/72cf730045d4333a?hl=en&q=structure+plugin+authoring#72cf730045d4333a
And the source is here:
http://code.google.com/p/jquery-plugin-dev/source/browse/trunk/jquery.plugin.js
EDIT:
I created a function that has similar functionality to that plugin:
jQuerify = function(fn) {
function plugin() {
var instantiate = false;
// check to see if it has any prototyped methods (we only need one iteration to do this)
for (var i in construct.prototype) {
instantiate = true;
break;
}
// if there are prototyped methods, return an instance (since an instance's return value won't vary)
// otherwise just call it using apply so the return value can vary
return instantiate
? new construct(this, arguments)
: construct(this, arguments);
}
function construct(parent, args) {
// 'this' will not mimic jQuery unless given the length property
this.length = 0;
this.selector = parent.selector;
this.context = parent.context;
// mimic 'this' in jQuery, but for the plugin namespace
Array.prototype.push.apply(this, $.makeArray(parent));
// return the constructors return value
// should be 'this' if you want to chain the new namespace
return fn.apply(this, arguments);
}
// copy all static properties and methods
for (var i in fn) {
plugin[i] = fn[i];
}
// allow .fn and copy all instance properties and methods; the last part is for IE
plugin.fn = construct.prototype = plugin.prototype = fn.prototype;
return plugin;
}
This allows you to add custom objects to jQuery as a plugin while using 'this' to refer to the selected objects and also allows you to have an unlimited depth to your namespace:
function test1() {
return this;
}
test1.prototype.getHtml1 = function() {
return $(this).html();
}
function test2() {
return this;
}
test2.prototype.getHtml2 = function() {
return $(this).html();
}
function test3() {
return this;
}
test3.prototype.getHtml3 = function() {
return $(this).html();
}
jQuery.fn.test1 = jQuerify(test1);
jQuery.fn.test1.fn.test2 = jQuerify(test2);
jQuery.fn.test1.fn.test2.fn.test3 = jQuerify(test3);
jQuery(function($) {
alert($('body').test1().getHtml1());
alert($('body').test1().test2().getHtml2());
alert($('body').test1().test2().test3().getHtml3());
});