JS Module Pattern: How to initialize a local object - javascript

I'm confused about how to initialize a local object in a JS Module implementation. I have a local variable (an object) that I try and access in the object literal I return; however, when I try to add a new property to that object it says it's undefined. But if I don't then I can easily set the value of the local object to anything else.
Here's my code:
var myModule = (function(){
var myLocalObj = {}; // I always get a warning in the IDE that this var is never read
return{
setObject:function(coll){
this.myLocalObj = coll; // this works just fine
this.myLocalObj.newProp = coll.prop // fails because 'myLocalObj' is undefined.
},
getObject:function(coll){
return this.myLocalObj;
}
};
})();
myModule.setObject(obj); // this is what I call after an ajax call is complete

The problem is myLocalObj isn't a property of the object returned, its a local var belonging to the scope. So, you can access directly using
setObject:function(coll){
myLocalObj = coll; // be aware! you're overriding the original {}
myLocalObj.newProp = coll.prop // now it works as expected
}
because the closure (setObject) has access to the scope variables.
You will need a getter as well to access the data from outside
getObject:function(){
return myLocalObj;
}
Or if you need to keep safe the reference
getProp:function(prop){
return myLocalObj[prop];
}
Hope you find it useful!

I'll explain why these lines are doing what you're seeing:
this.myLocalObj = coll; // this works just fine
this.myLocalObj.newProp = coll.prop // fails because 'myLocalObj' is undefined.
this.myLocalObj is undefined.
So undefined = 'some value' is failing silently. So "this works just fine" is not true.
this.myLocalObj.newProp is the same as undefined.newProp.
undefined has no property, newProp, hence the error.
Of course I haven't tested any of that, just winging it, like every good programmer should! :D

In you code, the this references the object returned. Therefore using this modifies the api and not myLocalObj. You might want to try something like this if you want the ability to assign the myLocalObj with something other than the empty object that is already there.
var improvedModule = (function(){
var myLocalObj = {};
var api = {
init: function(obj) {
if (obj) {
myLocalObj = obj;//if this is not an object the api may break doing this!!!
}
},
get: function(prop) {
if (myLocalObj[prop]) {
return myLocalObj[prop];
}
},
set: function(prop, val) {
myLocalObj[prop] = val;
}
};
return api;
})();
improvedModule.init({
foo: true,
bar: false
});
console.log(improvedModule.get('foo'));

Related

How to update object properties on external variable change

I once again stumbled over a behavior in Javascript that I don't understand. I need to update properties of an object as soon as a variable outside of the object is changed. The external variable is referenced in the object properties so I thought all I had to do is to change the variable externally and automatically have the property values changed.
Here's a simplified version of what the code looks like:
var serverPath = "123/";
var GetCurrentProductionApiConfig = {
URL: {
GetStart: serverPath + 'GetCurrentProduction?returnValue=start&',
GetEnd: serverPath + 'GetCurrentProduction?returnValue=end&',
Get: serverPath + 'GetCurrentProduction?returnValue=start&'
}
};
serverPath = "456/";
console.log(GetCurrentProductionApiConfig.URL.GetStart);
This will result in:
123/GetCurrentProduction?returnValue=start&
Is it because the variable has been copied (passed by value) rather than having a pointer on it (passed by reference)? And which way would be the correct one to update the properties?
Everything in JavaScript is pass by value however, it happens that the value of an object is its reference. However, the important thing here is that for primitives, will not get changes when a referenced variable changes:
var a = "world";
var obj = {
b: "hello" + a //evaluated once
}
a = "universe"; //does not modify obj.b which references a
console.log(obj.b); //helloworld
In order to have a dynamically evaluated string, you need to call a function or a method:
var a = "world";
var obj = {
b: function() {
return "hello" + a //evaluated every time the function is executed
}
}
console.log(obj.b()); //helloworld
a = "universe"; //will influence obj.b
console.log(obj.b()); //hellouniverse
However, that looks a bit "dirty" since it forces the caller to know to evaluate the property every time. It can also introduce inconsistency if some properties are plain strings, others functions and it's especially annoying if a property has to change from one to the other - you need to modify every place that calls this code to change, say, obj.c to obj.c().
Instead, using ES6+ you can define a getter for a property that will do the same as before but will hide the function call, so any time you read a property you actually evaluate code to return the result:
var a = "world";
var obj = {
c: "plain property"
}
Object.defineProperty(obj, 'b', {
get: function() {
return "hello" + a //evaluated every time the property is read
}
});
console.log(obj.b); //helloworld
a = "universe"; //will influence obj.b
console.log(obj.b); //hellouniverse
console.log(obj.c); //plain property

JavaScript: Setter for inner object

I have a simple object and constructor in Traditional JavaScript as follows:
function Test() {
this.data={};
}
Test.prototype={
set value(something) {
},
get value() {
return data[property];
}
};
var test=new Test();
Inside the object is another object, initially with no own properties.
I would like to write a Setter for value which sets a property on the inner object (data).
test.value.whatever=23;
Is there any way I can do this?
I expect that the Setter function could then finish the job with something like this:
set value() {
// how do I get property & value?
data[property]=value;
},
Here you go
function Test() {
this.data = {};
}
Test.prototype={
set value(v) {
this.data.whatever = v;
},
get value() {
return this.data.whatever;
}
};
var test = new Test();
test.value = 'hi';
console.log(test.value) // 'hi'
console.log(test.data) // {whatever: 'hi'}
Remember to put the data property in the constructor. Otherwise, if you put it into the prototype, it will be a shared property among every instance.
OK, I have an answer: as suggested by #Bergi & #damianmr, I used (and had to learn about) a Proxy object.
Here is a working version:
function Test() {
this.dataStore={};
this.data=new Proxy(this,{
set(target,property,value) {
target.dataStore[property]=value;
},
get(target,property) {
return target.dataStore[property];
}
});
}
Test.prototype={
};
var test=new Test();
test.data.whatever=23;
test.data.etc=46;
alert(`${test.data.whatever} ${test.data.etc}`);
As you can see:
I have an object called dataStore, and a proxy called data
The Proxy is set in the constructor
This is a simple abstracted case, but it also works for the more complex project I’m working on.
The only shortcoming is that IE doesn’t support Proxy, and the polyfills I have seen don’t like new properties.
That just means I will need to supply a functional alternative for Legacy Browsers, and wait for them to die out …

Is it possible to use a constructor in a Javascript object literal to avoid instantiation?

I have an object that needs certain properties to be set by execution instead of assignment. Is it possible to do this using a literal object notation?
I would like to be able to access the object's properties using this:
myObject.propertyName
...rather than this:
objInstance = new myObject();
objInstance.propertyName;
EDIT: to clarify, based on Bergi's answer, this is what I'm aiming to do:
var myObj = {
myInfo: (function() { return myObj.getInfo('myInfo'); })(),
getInfo: function() {
/* lots of execution here that would be redundant if done within myInfo */
}
}
// access the calculated property value
myObj.myInfo;
But this gives me the error myObj is not defined
I guess what you want is an IEFE, which you can put inside an object literal:
var myObject = {
propertyName: (function() {
var it = 5*3; // compute something and
return it;
}()),
anotherFunction: function() {…}
};
myObject.propertyName // 15
Maybe you also want to use the module pattern. Have a look at Simplest/Cleanest way to implement singleton in JavaScript?.
Thanks to Bergi to finding this, here is a final example what I wanted to do:
myObj = {
init: function() {
this.oneProperty = anyCodeIWant...
this.anotherProperty = moreCodeIWant...
// and so on
return this;
}
}.init();
myObj.oneProperty;
myObj.anotherProperty;
// and so on

replace object with new, or clear object fields?

I was lead to this question because for some reason I was having a problem setting a value on an object variable to false.
I had
var myObject{
checkValid = false,
self.getCheckValid = function(){
return checkValid;
}
self.setCheckValid = function(mode){
checkValid = mode;
}
}
objectVariable = new myObject;
when I ran objectVarible.setCheckValid(true), I would get the true value. But when I ran objectVariable.setCheckValid(false) the whole app would error out (except I'm developing in mobile and couldn't see the actual error returned).
But then I was wondering, if I can't set the mode to false, can I just re-initiate the entire object by calling objectVariable = new myObject; again. This will overwrite the old object with the new object and get me back to the initialized state, which is really what I'm looking for.
Is there a reason not to do this? Or is one method better than the other?
Any reason why I couldn't just set the checkValid to false?
The syntax for creating an object uses : instead of = to create a property. There is also no need to use .self to access the properties. Also when assigning the object to a variable you should use the syntax var myObject = {/**properties**/};
var myObject = {
checkValid:false,
getCheckValid: function(){
return this.checkValid;
},
setCheckValid: function(mode){
this.checkValid = mode;
}
};
Working Example: http://jsfiddle.net/PSYSM/
The accessors you have placed on the object are unnecessary, you have direct access to the checkValid property without the accessors.
var myObject = {
checkValid:false
};
alert(myObject.checkValid);
myObject.checkValid = true;
alert(myObject.checkValid);
Working Example: http://jsfiddle.net/JtfaJ/
Regarding using new with MyObject, this is not possible since you have declared an object literal. Only one instance of this object will exist, therefore you cannot create instances of the object. If you want to create instances you will need to create a object constructor. This can be done as follows:
function MyObject(){
this.checkValid = false;
}
var myObject1 = new MyObject();
myObject1.checkValid = true;
alert(myObject1.checkValid);
var myObject2 = new MyObject();
alert(myObject2.checkValid);
Working Example: http://jsfiddle.net/PzhUV/

Javascript: constant properties

In javascript, can I declare properties of an object to be constant?
Here is an example object:
var XU = {
Cc: Components.classes
};
or
function aXU()
{
this.Cc = Components.classes;
}
var XU = new aXU();
just putting "const" in front of it, doesn't work.
I know, that i could declare a function with the same name (which would be also kind of constant), but I am looking for a simpler and more readable way.
Browser-compatibility is not important. It just has to work on the Mozilla platform, as it is for a Xulrunner project.
Thank you a lot!
Cheers.
Since you only need it to work on the Mozilla platform, you can define a getter with no corresponding setter. The best way to do it is different for each of your examples.
In an object literal, there is a special syntax for it:
var XU = {
get Cc() { return Components.classes; }
};
In your second exampe, you can use the __defineGetter__ method to add it to either aXU.prototype or to this inside the constructor. Which way is better depends on whether the value is different for each instance of the object.
Edit: To help with the readability problem, you could write a function like defineConstant to hide the uglyness.
function defineConstant(obj, name, value) {
obj.__defineGetter__(name, function() { return value; });
}
Also, if you want to throw an error if you try to assign to it, you can define a setter that just throws an Error object:
function defineConstant(obj, name, value) {
obj.__defineGetter__(name, function() { return value; });
obj.__defineSetter__(name, function() {
throw new Error(name + " is a constant");
});
}
If all the instances have the same value:
function aXU() {
}
defineConstant(aXU.prototype, "Cc", Components.classes);
or, if the value depends on the object:
function aXU() {
// Cc_value could be different for each instance
var Cc_value = return Components.classes;
defineConstant(this, "Cc", Cc_value);
}
For more details, you can read the Mozilla Developer Center documentation.
UPDATE: This works!
const FIXED_VALUE = 37;
FIXED_VALUE = 43;
alert(FIXED_VALUE);//alerts "37"
Technically I think the answer is no (Until const makes it into the wild). You can provide wrappers and such, but when it all boils down to it, you can redefine/reset the variable value at any time.
The closest I think you'll get is defining a "constant" on a "class".
// Create the class
function TheClass(){
}
// Create the class constant
TheClass.THE_CONSTANT = 42;
// Create a function for TheClass to alert the constant
TheClass.prototype.alertConstant = function(){
// You can’t access it using this.THE_CONSTANT;
alert(TheClass.THE_CONSTANT);
}
// Alert the class constant from outside
alert(TheClass.THE_CONSTANT);
// Alert the class constant from inside
var theObject = new TheClass();
theObject.alertConstant();
However, the "class" TheClass itself can be redefined later on
If you are using Javascript 1.5 (in XUL for example), you can use the const keyword instead of var to declare a constant.
The problem is that it cannot be a property of an object. You can try to limit its scope by namespacing it inside a function.
(function(){
const XUL_CC = Components.classes;
// Use the constant here
})()
To define a constant property, you could set the writable attribute to false in the defineProperty method as shown below:
Code snippet:
var XU = {};
Object.defineProperty(XU, 'Cc', {
value: 5,
writable: false
});
XU.Cc = 345;
console.log(XU.Cc);
Result:
5 # The value hasn't changed

Categories

Resources