I have a function in which I'm using closure as follows:
function myobject() {
var width=300,
height=400,
bigjsondata = { } // assume this is a big variable ~ 300k
function obj(htmlelement) {
// plot a graph in this htmlelement based on bigjsondata
}
return obj;
}
var plot1 = myobject();
plot1('#holder1');
var plot2 = myobject();
plot1('#holder2');
the variable bigjsondata contains a large dataset. The question is: does it allocate memory for bigjsondata whenever I create a variable var a = myobject() ?
Can it lead to memory problems if a lot of instances are created?
If so what is the best way to load it only once? (bigjsondata does not change)
Edit: At the end I would like myobject to be globally accessible.
not sure what you are trying to achieve, this should provide you with some private storage on different levels:
var privateStorage = function () {
// only 1 copy total
var bigJsonData = {...}
return function() {
// 1 copy for each instance
var instanceData = {...}
return function() {
// something to do many times per instance
return something_useful
}
}
}(); // returns function that privatelly knows about bigJsonData
var a = privateStorage(); // a is now 1st instance of the inner-most function
var b = privateStorage(); // a and b share the SAME bigJsonData object, but use different instanceData objects
a1 = a();
a2 = a();
Generally - yes, you code looks like creating a new instance for the bigjsondata each time you make a new myObject(); To get arround the issue, you can use anonymous initialization function like this:
myObject = null;
(function() {
var bigjsondata = { ... } // construct you large object here;
function myObjectInternal() {
// you can access `bigjsondata` from here.
// do not change `bigjsondata`, since it will now
// use the changed value in all new instances of `myObjectInternal`
}
myObjectInternal.prototype = {
data: function(_) {
// you can access `bigjsondata` from here too
}
};
myObject = myObjectInternal;
})();
This will create an anonymous function that is called immediately and only once (like a singleton). Inside the function, bigjsondata is a a closure to the myObjectInternal function, which is visible only in the anonymous one. That is why you define the outer global variable myObject, to latter make it point to the myObjectInternal function/object.
Define myObjectInternal as you would have myObject and you're good to go. So, in the following code:
var instance1 = new myObject();
var instance2 = new myObject();
it will use the same bigjsondata for instance1 and instance2
I would suggest going for an object oriented approach for this.
function obj (htmlelement)
{
this.htmlelement = $(htmlelement);
}
obj.prototype.htmlelement = null;
obj.prototype.bigjsondata = {};
obj.prototype.width = 300;
obj.prototype.height=400;
obj.prototype.plot = function ()
{
var htmlelement = this.htmlelement;
var bigjsondata = this.bigjsondata;
var width = this.width;
var height = this.height;
//plot graph here;
}
var plot1 = new obj('#holder1');
var plot2 = new obj('#holder2');
plot1.plot();
plot2.plot();
Here, the same bigjsondata will be shared among all objects of obj.
Related
Trying to implement a Javascript sandboxing scheme and now I've run into a bit of a wrinkle. I need to pass a "context" parameter to the code which will essentially serve as a handle to the "global" object, but so far no luck.
To illustrate the problem with a simple example, consider this bit of code:
var foo = new Function(" this.baz = this.mux; return this ");
foo.mux = "mux";
foo.call();
console.log(foo.baz);
console.log(foo.toString());
Output:
$> undefined
$> function anonymous() { this.mux; return this; }
It obviously doesn't work because the Function object doesn't seem to get it's own this like ordinary functions created with new.
So...is there any way to "reseat" a Function's this to point to itself beforehand (or just any other way around the issue)?
EDIT
Okay, so from what I understand from the comments section I'm going to need a constructed object.
var foo = new Function(" return new function(){ this.baz /* = ?? */; return this; } ");
Is there a way to somehow access the enclosing anonymous function's properties? Like "this.mux = foo.mux" (except of course "foo" isn't visible from that scope)?
I think your getting confused on what new Function( does,. It does not create an instance of an object, it just create a function. So like any object instances you will also need to use new on these.
So you need 2 steps..
create the function that you will be creating an object from..
with this function create an instance using new..
Below is a simple example..
var fcreate =
new Function('global', "this.global = global");
var f = new fcreate("hello");
console.log(f.global);
If your not bothered about instances, we can forget about this altogether, and just create a captured scope as a parameter..
eg..
var f = new Function("global", "console.log(global)");
f("This is a global to function");
f("This is another one");
You can pass foo as a parameter of call:
var foo = new Function(" this.baz = this.mux; return this ");
foo.mux = "mux";
foo.call(foo); // <-- this
Edit: Although the code above works, I wouldn't recommend it. You will be better off creating the function/class foo:
var Foo = function(mux){
this.baz = mux;
}
var foo = new Foo("mux");
console.log(foo.baz);
The best I could come up with that actually works.
var foo = new Function(" this.baz = this.mux; return this ");
var context = { mux: "mux" };
foo = foo.bind(context);
foo();
// context.baz == "mux"
Alright so this is in fact doable, and it's basically an extension of Keith's answer:
function verify(condition)
{
console.log(condition === true ? "pass" : "fail");
}
function test()
{
if(!(this instanceof test))
return new test();
var foo = new Function("mux", "return new function(){ this.baz = mux; return this; } ");
var bar = new foo(null);
verify(bar.baz === null);
var zim = new foo(this);
verify(zim.baz === this);
var qud = new foo(global);
verify(qud.baz === global);
};
test();
Output:
pass
pass
pass
A sincere thanks to everyone for helping me figure this one out - cheers!
* EDIT *
As per Keith's comments, the correct implementation would simply be:
function verify(condition)
{
console.log(condition === true ? "pass" : "fail");
}
function test()
{
if(!(this instanceof test))
return new test();
var foo = new Function("mux", "this.baz = mux; return this; ");
var bar = new foo(null);
verify(bar.baz === null);
var zim = new foo(this);
verify(zim.baz === this);
var qud = new foo(global);
verify(qud.baz === global);
};
test();
I could create an object with some methods, and later add a property to it as follows:
var myObj = (function () {
var my = {};
my.method1=function(){}
my.method2=function(){}
my.method3=function(){}
return my;
}());
myObj.myProperty=123;
How could I create the object first and add a property, and then later add the methods afterwards?
myObj={};
myObj.myProperty=123;
//How do I add the above methods to myObj?
I guess there are two solutions:
Merge the objects:
var myObj = {...};
// ...
var objWithMethods = (function() { ... }());
Object.assign(myObj, objWithMethods);
(Object.assign is an ES6 methods. A polyfill can be found in the link, libraries often also provide a method with similar behavior).
Pass the object the methods should be assigned to as argument:
var myObj = {};
myObj = (function (obj) {
var my = obj || {};
my.method1=function(){}
my.method2=function(){}
my.method3=function(){}
return my;
}(myObj));
You can do an extend operation using an existing object
var myObj = {...}
var myAdditionalMethods = { someMethod : function(){ } }
//extend the object
for(var i in myAdditionalMethods)
if(!myObj.hasOwnProperty(i))
myObj[i] = myAdditionalMethods[i];
there are a lot of libraries that have this functionality built in, but that is how you would do it without one
Even prototype can add the functions to original object.
var myObj = function() {
this.myProperty = 123;
}
myObj.prototype.method1 = function method1() {
alert("method1")
}
myObj.prototype.method2 = function method2() {
alert("method2")
}
var newObj = new myObj();
newObj.method1();
newObj.method2();
console.log(newObj)
Is there a name for describing the different ways you can define an object in Javascript?
There is this method which is more 'class-like' :
function MyObject() {
this.aMethod= new function(){
};
this.anotherMethod = new function(){
};
}
And this other technique which is more 'dynamic'.
MyObject = new Object();
MyObject.aMethod= new function(){
};
MyObject.anotherMethod = new function(){
};
I have been using both of these techniques in various ways, and i understand the benefits of each, but for the life of me, I don't have any idea how to call these two techniques when discussing this with colleauges.
Do these techniques have names?
In the first case MyObject is a constructor function, since it is supposed to be called with new:
var obj = new MyObject();
In the second case, MyObject is just an object and you assign properties to it. It does not have a special name.
Note that in both cases MyObject has different values. MyObject in the second case is equivalent to obj.
A third way is to use an object initilizer or "object literal":
var obj = {
aMethod: function(){},
anotherMethod: function(){}
};
Your first example is an Object Constructor, while the second is simply adding public methods as properties to an object. As a side note, for an even more "class-like" behavior take a look at the module pattern:
var MyObject = (function() {
var privateStaticVariable = 0;
var my = function() {
var self = this;
var privateInstanceVariable = 0;
function privateInstanceMethod() {
}
self.publicInstanceVariable = 0;
self.publicInstanceMethod = function() {
};
};
function privateStaticMethod() {
};
return my;
});
Can I kindly ask for explanation:
What does the code below represent? Does it create a DndUpload Ojbect? Or, does it create a DndUpload() function? What I miss is the statement new normally present during JavaScript objects creation. Can I kindly ask for some explanation, as I am confused.
var DndUpload = function (inputElem)
{
this.input = inputElem;
this.dropZone = null;
this.isDragging = false;
this.init();
};
As far as I know this is the way to create object in Javascript:
var myObject = new function()
{
};
If you have any link with explanation, that would help. Thank you.
It's a worse way of writing this:
function DndUpload(inputElem)
{
this.input = inputElem;
this.dropZone = null;
this.isDragging = false;
this.init();
}
which is a function declaration. It does not create an instance of DndUpload. Technically, it does create an object – its name is DndUpload and it is an instance of Function. To create an instance of this "class:"
var instance = new DndUpload(document.getElementById('someInputId'));
var myObject = new function()
{
};
Defines an anonymous constructor function and then instantiates a new object using the anonymous constructor function. It could have been replaced with var myObject = {}.
var DndUpload = function (inputElem)
{
this.input = inputElem;
this.dropZone = null;
this.isDragging = false;
this.init();
};
Defines a constructor function (technically an anonymous constructor function assigned to a variable). You can then create objects of this "class" by invoking the constructor function with new:
var dndUploadObject = new DnDUpload(),
anotherUploadObject = new DnDUpload(); //2 unique DnDUpload objects
the code you have essentially creates a constructor for a "class" it's more or less a blueprint for an object.
It then puts that constructor into a variable called DndUpload
So you can now make an object with
var myObject = new DndUpload(input elem)
Quick and strange question:
I have an object (in this example is small but in the project is larger):
var myObject = {
hello: 1, // easier I think
'hey.ya': 5 // quite impossible but the first option is valid too
}
then I want to pass somehow to a function and use "hello" for example in a closure like this
function x(){
// my closure
return function(){this.init = function(){alert(hello)}, this.heyYa = function(){alert(/* I do not know how to call the other hey.ya variable */)}}
}
var myClass = x(), instance = new myClass(); instance.init();
thanks!
You need to use the myObject
var myObject = {
hello: 1,
'hey.ya': 5
}
function x(obj){
return function(){
this.init = function(){
alert(obj.hello)
},
this.heyYa = function(){
alert(obj['hey.ya'])
}
}
}
var myClass = x(myObject);
var instance = new myClass();
instance.init(); // alerts '1'
instance.heyYa(); // alerts '5'