Calling a function which returns several values - javascript

If a function returns more than one calculation and it's convenient to reuse that one function in few separate instances, is it best to store the result of the calculations in an internal array and just pull out of the array a calculation that's needed on that particular call or is there a more efficient way?
var calcFunction = function() {
var ar = [];
var calcA = ...
ar.push(calcA);
var calcB = ...
ar.push(calcA);
return ar;
}

If you're function is really long, it'll be much more efficient to use the array every time, however, this distance gets shorter and shorter as the function gets shorter. However, this isn't the only reason to use the array. Calling the function several times with the same values is essentially code duplication, which is a standard code smell.
Overall, if you can call a method as few times as possible, you've done your job right.

Here are options off the top of my head in order of my preference. Performance, if truly releavant, you should benchmark. Preference depends on your code and its purpose.
// If independent and appropriate, split it into two separate functions
// modularization into smaller reusable building blocks is good
var calcAFunction = function() {
var calcA = ...
return calcA;
}
var calcBFunction = function() {
var calcB = ...
return calcB;
}
// Returning an array
var calcFunction = function() {
var ar = [];
var calcA = ...
ar.push(calcA);
var calcB = ...
ar.push(calcA);
return ar;
}
// Returning an object, disadvantage you must maintain key names as opposed to index
var calcFunction = function() {
var o = {};
var calcA = ...
o.key1 = calcA;
var calcB = ...
o["key2"] = calcB;
return o;
}
// Calling it with a callback function
var calcFunction = function(cb) {
var o = {};
var calcA = ...
var calcB = ...
cb(calcA, calcB)
}
calcFunction(function(A, B) {})
UPDATE
// Returning an object, disadvantage you must maintain key names as opposed to index
var calcFunction = function() {
var o = {};
var calcA = ...
o.key1 = calcA;
var calcB = ...
o["key2"] = calcB;
return o;
}
var retObj = calcFunction();
//you can access retObj.key1 and retObj.key2

Related

node.js how to make one variable change apply to another one aswell?

Is there some kind of way of having some kind of "shared" variable? What I want to do is this:
var id = 5;
var player = new Player(id);
var array1[0] = player;
var array2[0] = player;
array1[0].id = 8
console.log(array1[0]); //8
console.log(array2[0]); //8
In JavaScript, you do not store an object directly in a variable, but rather a reference to the object.
That means, you can have two variables that point to the same object - you simply copy the reference:
var a = {test: "test"};
var b = a;
console.log(a === b) // true
In this case, if you mutate the object via a and later read it via b, you will see the changes.
With the right implementation of Player, you can make that work for you:
var Player = function(id) {
this.id = id;
}
Player.prototype.setId = function(id) {
this.id = id;
}
Player.prototype.getId = function() {
return this.id;
}
var player = new Player(5);
console.log(player.getId()); // 5
var arrA = [];
var arrB = [];
arrA.push(player);
arrB.push(player);
console.log(arrA[0].getId()); // 5
console.log(arrB[0].getId()); // 5
arrA[0].setId(10);
console.log(arrA[0].getId()); // 10
console.log(arrB[0].getId()); // 10
Check MDN for more info on working with objects.

Create deep object from string like "obj.obj1.obj2.data'

I'm starting with unit testing. I need to create some fake data to run the tests. So let's say inside a stubbed method I'm passing an obj as an argument and I do things with obj.obj1.obj2.data inside the function. Is there a way to set this fake object? So, given:
obj.obj1.obj2.data
It creates:
obj = {
obj1: {
obj2: {
data: 'whatever'}}}
So it would be at the end something like:
var obj = creator('obj.obj1.obj2.data', 20);
Assuming the string is only a set of objects (no arrays) this should be fairly straightforward. Just split the input string on . and then use a while loop to do the nesting.
function creator(str,val){
var tree = str.split('.');
var ret = {};
var cur = ret;
while(tree.length){
var name = tree.shift();
cur[name] = tree.length ? {} : val;
cur = cur[name];
}
return ret;
}
document.querySelector("#out").innerHTML = JSON.stringify(creator('obj.obj1.obj2.data',20));
<div id="out"></div>
Just in case anyone else in interested, I created a simple npm module with the function below (https://github.com/r01010010/zappy) check it out:
var objFrom = function(str, last_value){
var objs = str.split('.');
var r = {};
var last = r;
for(i=0; i < objs.length; i++) {
if(i !== objs.length - 1){
last = last[objs[i]] = {};
}else{
last[objs[i]] = last_value;
}
}
return r;
}
var obj = objFrom('obj1.obj2.data', 20);
console.log(obj.obj1.obj2.data);

How to recursively merge 2 javascript objects?

I have 2 objects that I need to merge and keep all properties in tact, tried with jQuery $.extend but I cant get it to work . I tried all posts with how to merge javascript objects but simply cant get this to work.
var thz_icon_source = {"Spinners":["spinnericon1","spinnericon2"],"Awesome":["awesomeicon1","awesomeicon2"]};
var fa_icon_source = {"Spinners":["faspinner1","faspinner2"],"Awesome":["faawesome1","faawesome2"]};
var new_source ={};
$.extend(new_source,fa_icon_source,thz_icon_source);
console.log(thz_icon_source);
console.log(fa_icon_source);
console.log(new_source);
desired output should be like
{
"Spinners":["faspinner1","faspinner2","spinnericon1","spinnericon2"],
"Awesome":["faawesome1","faawesome2","awesomeicon1","awesomeicon2"]
}
This post Merge two json/javascript arrays in to one array has a simple object mine is not same as that one.
Demo
function mergeJSON(json1,json2)
{
var result = json1 ;
for (var prop in json2)
{
if (json2.hasOwnProperty(prop))
{
result[prop] = result[prop].concat(json2[prop]);
}
}
return result;
}
$.extend merges in missing properties, it doesn't combine the properties that are in common. You need to write a loop.
var thz_icon_source = {
"Spinners": ["spinnericon1", "spinnericon2"],
"Awesome": ["awesomeicon1", "awesomeicon2"]
};
var fa_icon_source = {
"Spinners": ["faspinner1", "faspinner2"],
"Awesome": ["faawesome1", "faawesome2"]
};
var new_source = {};
// First add in the new elements from thz_icon_source
$.extend(new_source, fa_icon_source, thz_icon_source);
// Now merge the common elements
$.each(fa_icon_source, function(k, e) {
if (thz_icon_source.hasOwnProperty(k)) {
new_source[k] = e.concat(thz_icon_source[k]);
}
});
console.log(thz_icon_source);
console.log(fa_icon_source);
console.log(new_source);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can use this prototype to merge 2 or more objects the way you want it:
Object.prototype.assignDeep = function() {
var self = this;
Object.keys(arguments).forEach(obj => {
Object.keys(self).forEach(val => {
if (arguments[obj].hasOwnProperty(val)) {
var tmp = arguments[obj][val] instanceof Array ? arguments[obj][val] : [arguments[obj][val]];
self[val] = self[val].concat(tmp);
}
});
});
return self;
}
var thz_icon_source = {"Spinners":["spinnericon1","spinnericon2"],"Awesome":["awesomeicon1","awesomeicon2"]};
var fa_icon_source = {"Spinners":["faspinner1","faspinner2"],"Awesome":["faawesome1","faawesome2"]};
var b = thz_icon_source.assignDeep(fa_icon_source);
console.log(b);
You should use a loops with .concat():
function objectConcatArrays(){
var a = arguments, o = {};
for(var i=0,l=a.length; i<l; i++){
for(var p in a[i]){
if(p in o){
o[p] = o[p].concat(a[i][p]);
}
else{
o[p] = a[i][p];
}
}
}
return o;
}
var thz_icon_source = {"Spinners":["spinnericon1","spinnericon2"],"Awesome":["awesomeicon1","awesomeicon2"]};
var fa_icon_source = {"Spinners":["faspinner1","faspinner2"],"Awesome":["faawesome1","faawesome2"]};
var res = objectConcatArrays(thz_icon_source, fa_icon_source);
console.log(res);
Each argument represents an Object of Arrays. Add more if you want.

Nested callback in javascript

In my program, I have declared an object myObject like this :
function myObject()
{
this.start=start;
function start(callbackFunction)
{
// Do something with callbackFunction
}
}
In my main() method, I create objects and I want to start nested callback like this :
var myObject1 = new myObject();
var myObject2 = new myObject();
var list = [];
list.push(myObject1);
list.push(myObject2);
var result = function() {};
var obj;
for (var i=list.length-1; i>=0; i--) {
obj = list[i];
result = function() { obj.start(result);}
}
result(); // I want to do myObject1.start(myObject2.start)); e.g. a nested callback
I don't understand why it doesn't work.
How can I correct my code ?
The result variable is redefined after each iteration.
Your need to set your function like so :
var myObject1 = new myObject();
var myObject2 = new myObject();
var list = [];
list.push(myObject1);
list.push(myObject2);
var result= function() {};
for (var i=list.length-1; i>=0; i--) {
var obj = list[i];
result = obj.start.bind(obj, result);
}
result();
Using the bind method will force the state of the variable to be saved at each iteration.
The problem is that you are not using closures properly.
In your for loop you declare a function that uses a variable from the outer scope (result). When the for loop ends, the result variable will contain the last function defined, instead of the one defined at step i, as you would expect.
One solution as you so very well hinted in a comment is recursivity:
function myObject(name)
{
this.name = name;
this.start= function(callbackFunction) {
console.log(this.name);
// Do something with callbackFunction
callbackFunction();
};
}
var myObject1 = new myObject(1);
var myObject2 = new myObject(2);
var list = [];
list.push(myObject1);
list.push(myObject2);
var runner = function(list, currentIndex) { // recursive function
if (currentIndex < 0) return function(){ console.log('INITIAL');};
return function(){
list[currentIndex].start(runner(list, currentIndex-1));
};
};
runner(list, list.length-1)();
DEMO: http://jsbin.com/ukeBUweG/2/edit
One last note, the solution above tries to stay true to your initial code. It is not
obj1.start(obj2.start(function(){}))
, but
function(){ obj1.start(function(){ obj2.start(function(){}) })}();

Handling of array; returned by methods in iOS UI Automation

I have been able to use all the methods for automating iphone app test except with ones which returns array... e.g elements()
I have tried to do it using declaration of array as
var arr = [];
var arr = UIATarget.localTarget().frontMostApp().mainWindow().tabBar().elements();
UIALogger.logPass("result"+ arr[0]) // just to get first element
But it is not working
Can someone ans how to handle array. What is the correcting required?
What exactly do you want from such array?
Here is an example how to handle array of elements:
function getAllNamesInList (list, index){
var elem_list = list[index].elements();
var elem_count = elem_list .length;
var names = [];
var elem_name;
for (var elem_ind = 0; elem_ind < elem_count ; elem_ind++){
elem_name= elem_list [cell_ind].name();
if (!elem_name){fail ("TEST_INFO: Empty Element name!!!");}
names.push(elem_name);
}
return names;
};
Here is usage example of this function():
Your case:
var app = UIATarget.localTarget().frontMostApp();
var window = app.mainWindow();
var arr = window.tabBar()
var current_names = [];
current_names = getAllNamesInList (arr , 0);
UIALogger.logMessage ("Here are ALL names from array " + current_names );
Other possible lists which can be transferred and used within this function():
var table_views = window.tableViews();
var tab_bar = app.tabBar();
var nav_bar = app.navigationBar();

Categories