Instances Conflicting - JSON objects - javascript

I'm not doing something right.
Trying to create 2 instances of data models off my json model template file and use them but I'm obviously not getting 2 different instances of the model.
myModel.json
{
"id": null
}
myNodeModule.js
var myModel = require('../../entities/myModel');
module.exports = {
find: function *(id){
var myModelInstance1 = myModel;
myModelInstance1.id = 1;
var myModelInstance12 = myModel;
myModelInstance12.id = 2;
found.push(myModelInstance11);
found.push(myModelInstance12);
console.log("id: " + found[0].id);
}
Problem: it logs "2" because for some reason it applies the last initialization for myModel1.
So how do you create 2 separate object instances of myModel.json?

Create a function instead, which returns the object and call it.
function myModelFact(){
return {
"id": null
}
}

The problem is that requiring a JSON document creates an object instance, but returns a reference to that instance (objects are passed/assigned by reference). That means that when you assign myModel, which is a reference to the object to another variable, you are essentially assigning a pointer to that same object. Consequently, if you modify the reference, the single instance changes and that change reflects on all references to that instance.
Try something like this instead:
function _getModelInstance() {
return require('../../entities/myModel');
}
module.exports = {
find: function(id){
var myModelInstance1 = _getModelInstance();
myModelInstance1.id = 1;
var myModelInstance12 = _getModelInstance();
myModelInstance12.id = 2;
found.push(myModelInstance11);
found.push(myModelInstance12);
console.log("id: " + found[0].id);
}
This code will create a new instance of the object from the JSON document on demand.

Related

Calling Factory/Function From String

I am reading a config file which contains a mapping of Angular Factories/Function names. The Factory/Function names are stores as strings in the mapping. I am wondering how would I be able to execute the Factory/Function I have read from config?
None of these factories are accessible on window otherwise I could call window[factory][functionName]().
Would I have to resort to something like:
var factory;
var factoryName = getFactory(config.sendTelemetry);
if (factoryName === 'TelemetryFactory') {
factory = TelemetryFactory;
} else if (factoryName === 'DebugFactory') {
factory = DebugFactory;
}
factory[functionName]();
Sample config file:
// Sample config file
var config = {
'sendTelemetry': {
'factory': 'TelemetryFactory',
'functionName': 'sendTelemetry'
},
'logDebug': {
'factory': 'DebugFactory',
'functionName': 'logDebug'
}
}
If the functions are just normally scoped functions, you can do a one-off creation of a lookup map from name to function reference to avoid the long switch statement:
var funcMap = {
TelemetryFactory: TelemetryFactory,
DebugFactory: DebugFactory
};
or to avoid the (potentially error-prone) repetition, by using each function's .name property and constructing the map from an array of function references:
// build lookup map
var funcs = [ TelemetryFactory, DebugFactory ];
var funcMap = {};
funcs.forEach(function(f) {
funcMap[f.name] = f;
});
In ES6 it becomes even simpler, because ES6 has an object literal syntax where you can pass the name of a variable (or function) and it automatically creates a key with that variable's name and value:
let funcMap = { TelemetryFactory, DebugFactory };
Whichever of the three methods above you use to build the map, dispatch is then a trivial operation via the map:
funcMap[factoryName]();
It looks like you'd need to evaluate the strings first:
eval(factory[functionName])();
Hope this helps :)

Object assignment does not work in this angularjs controller

Inside my angularjs controller, I try to assign an object into a $scope.XX object. For some reason, it cannot work. Here is a simplified version of the code inside the angularjs controller.
$scope.XXX = {};
polling_interval_ms = 100;
var poll = function (ChartObj, polling_interval_ms) {
var processedObj = {};
processedObj = processDataChart(data_Chart); //data_Chart is object that contains data that changes in real-time
ChartObj = Object.assign(processedObj);
console.log(ChartObj);
$timeout(function () {
poll(ChartObj, polling_interval_ms)
}, polling_interval_ms);
};
poll($scope.XXX, polling_interval_ms);
console.log($scope.XXX);
The strange part is the output of console.log(ChartObj); shows that data has been assigned to the object. However, the output of console.log($scope.XXX) is empty. I was expecting $scope.XXX to contain same data as ChartObj. What did I do wrong?
In javascript all parameters in function is reference. So when you change reference - you not change referenced object.
In your case you can use Object.assgin in a bit different way
Object.assign(ChartObj, processedObj);
because
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
Or pass wrapper for object XXX, in this case it a $scope
$scope.ChartObj = {};
polling_interval_ms = 100;
var poll = function (wrapper, polling_interval_ms) {
var processedObj = {};
processedObj = processDataChart(data_Chart); //data_Chart is object that contains data that changes in real-time
wrapper.ChartObj = Object.assign(processedObj);
console.log(wrapper.ChartObj);
$timeout(function () {
poll(wrapper, polling_interval_ms)
}, polling_interval_ms);
};
poll($scope, polling_interval_ms);
console.log($scope.ChartObj);
Use
$scope.XXX
instead of ChartObj because
your are assigning value to
ChartObj
and
$scope.XXX
is not a refrence type

creating one var object vs multiple var

For better code structure, I want to use a javascript object holding all properties instead of using multiple vars:
// 1. WAY
// This returns an error, as _inp cannot be accessed by input_value
// Uncaught TypeError: Cannot read property 'value' of undefined
var ref = {
_inp: input.target,
input_value: _inp.value,
....
};
// 2. WAY
// When using this, it works
var ref = {
_inp: input.target,
input_value: input.target.value,
....
};
// 3. WAY
// This obviously works, too.
var
_inp = input.target,
input_value = _inp.value,
My Question is, why does 3. Way works and 1.Way doesnt?
In example 1, _inp will be a property of an object. It isn't a variable. You can only access it from a reference to the object (and it won't be a property of the object until the object exists, which will be after the object literal has been evaluated, see also Self-references in object literal declarations).
Because _inp will only be filled in with the input.target value after passing through the entire var ref = { ... }; statement. This means that when you try to use it, it doesn't exist yet.
The 1st way don't work because you refers to "_inp" which is not an existing var. and the ref object is not fully created (that's why input_value: this._inp.value won't work either)
To create objects and assigning values to its properties, you can use a function (I keep most of your code):
var ref = {
_inp: input.target,
input_value: null,
init: function()
{
this.input_value = this._inp.value;
}
};
ref.init();
console.log(ref.input_value); // will contains the same as input.target.value
but usually, people create objects with all property with default values, and pass an argument to their init function:
var ref = {
_inp: null,
input_value: null,
init: function(input)
{
if (input)
{
this._inp = input.target;
this.input_value = input.target.value;
}
}
};
var input = {target:{value:"foo"}};
ref.init(input);

Prototype chain - setting key on one object affects a sibling object?

I am working on my first JS project that involves inheritance and the prototype chain, and I am confused about why the creation of one object with specific data is affecting the data already in place on my second object.
The goal is to have a set of basic defaults in the full_params object literal in the "parent" object, and have some more specific defaults in the default_params object literal in the "child" object.
The child object specificRequest takes an array argument for its constructor function, adds those to its default_params, and then call the setOptions function of its prototype to add those to the full_params.
The problem is that when I create one specificRequest object and initialize it, it works fine, but then when I create a second specificRequest object, the full_params is already the same as
that of the first.
This is probably something very simple from a misunderstanding of how prototype works...
/////// PARENT OBJECT
function baseRequest(custom_params) {
var key;
this.full_params = {
"SignatureVersion": "2",
"Timestamp": Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd'T'HH:mm:ss'Z'")
};
this.custom_params = custom_params;
}
baseRequest.prototype.setOptions = function(arg_options) {
var key;
if (typeof arg_options === "object") this.custom_params = arg_options;
// If an object of request options is passed, use that. Otherwise use whatever is already in the custom_params object.
for (key in this.custom_params) {
this.full_params[key] = this.custom_params[key];
}
}
///////// CHILD OBJECT
function specificRequest(mySKUList) {
var i;
this.mySKUList = mySKUList;
this.default_params = {
"Action": "myAction",
"Version": "2011-10-01"
};
for (i = 0; i < this.mySKUList.length; i++) {
var temp_sku = this.mySKUList[i];
var temp_sku_name = "SellerSKUList.SellerSKU." + (i + 1);
this.default_params[temp_sku_name] = temp_sku;
}
this.setOptions(this.default_params);
}
specificRequest.prototype = new baseRequest
///// Function to run
function testfoo() {
var skulist1 = ["AR6100", "AR6102", "WB1234"]
var skulist2 = ["XY9999"]
var req1 = new specificRequest(skulist1);
var req2 = new specificRequest(skulist2);
// Req1 has AR6100, AR6102, and WB1234 as parameters, as expected
// Req2 should only have XY9999, but instead has XY9999, AR6102, and WB1234
}
Well you have tied a concrete instance of the parent class to be the prototype of the child class with this line:
specificRequest.prototype = new baseRequest
Instead, don't instantiate the parent class at all:
specificRequest.prototype = Object.create( baseRequest.prototype );
Also, call super() equivalent when constructing a child instance:
function specificRequest(mySKUList) {
baseRequest.call( this );
...
}
And please start constructor names with UpperCase.

JavaScript Object Creation Pattern

I was reading an article here:
http://javascriptweblog.wordpress.com/2010/03/16/five-ways-to-create-objects/
It tells about five ways of creating objects. But my question is one of his way (3) is:
myApp.Notepad = function(defaultFont) {
var that = {};
that.writeable = true;
that.font = defaultFont;
that.setFont = function(theFont) {
that.font = theFont;
}
return that;
}
myApp.notepad1 = myApp.Notepad('helvetica');
As per author, we can use it when multiple instances are needed we can use any pattern from 3 (above) to 5.
But as far as I know, we do need to use this keyword which reflects back newly created instances and refers to only that instance. However above, author uses that object instead of this and also there is no new keyword used above. How will it apply to multiple object instances ? Is it essentially same as using this?
In your example, that is a new object created by this line:
var that = {};
The function then proceeds to set the properties of this object.
On the other hand, this is used with a constructor function -- when called using new, a new object is automatically created and passed to the function as this. The same example could be written as:
myApp.Notepad = function(defaultFont) {
this.writeable = true;
this.font = defaultFont;
this.setFont = function(theFont) {
this.font = theFont;
}
}
myApp.notepad1 = new myApp.Notepad('helvetica');
One advantage of the using the object literal constructor (your code) that hasn't been pointed out yet is that when you are creating a new instance of an object, the new keyword is not necessary. Or in other words, if you simply forget to use the new keyword, your code will still run as intended as you are no longer relying on the use of the new keyword to give the scope of this to your newly created object in your constructor function; The that object is now taking care of the scope for you.
This is the approach that the YUI library (and Douglas Crockford) takes for constructors.
Consider the following simple constructor:
var Car = function(model){
this.model = model;
};
If you were to call Car('Dodge Viper'); or even var MyCar = Car('Dodge Viper');, the this in the function would actually refer to the global window object. So now the property Model above is actually a global variable, which is probably not what was intended.
var Car = function(model) {
var that = {};
that.model = model;
return that;
};
// Both work the same.
var MamsCar = new Car("Mini Cooper"); // with 'new'
var DadsCar = Car("Bugatti Veyron"); // without 'new'
alert("Mam's car is a " + MamsCar.model + " and dad's car is a " + DadsCar.model);

Categories