3

Goal

I have a working function (JSFiddle). On numerous occasions throughout a script the function runs sequentially. In these instances, there is a lot of repetitious code that I would like to consolidate.

Ideally changing code like this:

functionName("First_item") + 
functionName("Second_item") + 
functionName("Third_item") + 

To something like this:

functionName("First_item", "Second_item", "Third_item");

The function will run for each item in the list so the result is the same but the code more elegant and maintainable.

Notes:

  • I’m not looking to use any libraries (e.g. jQuery) to accomplish the goal.

Solution

  1. Amit Joki’s answer kindly noted I could use arguments. When I implemented the code, the modified function (JSFiddle) only returned the output string for the first argument / item.

  2. Vanice’s answer pointed out the eventual solution.

    • Make one string from the output of all arguments / items by concatenating (joining) the output strings within the for loop (with the use of +=).
    • Return the concatenated output by placing the return outside of the for loop.

Example

Working solution (JSFiddle).


Thanks

Thank you very much to everyone for their time and help on this. I really appreciate it!

  • 2
    Sounds a lot like `Array.prototype.reduce`, or `Array.prototype.map` followed by `.join()`. Or you simply use a variable number of arguments. – Zeta Nov 24 '14 at 14:52
  • *"This works fine but is inefficient"*? Inefficient? Or not elegant? – Zeta Nov 24 '14 at 14:55
  • @Zeta Both I think! When I say inefficient I don’t mean the code runs slowly. Rather, the same thing can be 'said’ with far less code. Therefore, it would be more efficient to write in a different considering the overall quantity of times I use the function within the script. Perhaps redundant may have been a better expression than inefficient. Thank you kindly. –  Nov 24 '14 at 15:37
  • 1
    what you should say, is that you want your code to be more maintainable, as maintainability uses less code. I am still strongly recommending usage of either lodash, or underscore. This is because they handle a lot of caveats you'll run into (gothcas, if you will) - why re-invent the wheel. – docodemore Nov 24 '14 at 15:58

4 Answers4

5

Leveraging Javascript's Prototype OOP: You can add an each function to Array's themselves, so every array in your code that will automatically have an inhereted each function.

Array.prototype.each = function(callback){
    for (var i =  0; i < this.length; i++){
        callback(this[i]);
    }
}

Usage:

myArray.each(myCoolFunction) ['something','somethingelse',somethingother'].each(myCoolFunction)

myArray.each( function (item) {
 // if your item has a method
 item.Something();
 // if you'd like to call a function on the item:
 doSomething(item);
});

caveats:

Because javascript is an asynchronous language that is interpreted differently across various browsers and inherently handles primitive objects and complex objects differently, it is highly recommended usage of underscore or lodash. You can also make your own, but you'll need ensure the objects passed through will be handled by the functions properly. This may include workarounds or creating special callback functions for different object types that are passed through your each function.

For more information: Is JavaScript a pass-by-reference or pass-by-value language?

Libraries you should seriously consider:

lodash: https://lodash.com/docs#forEach

_([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
// → logs each number and returns '1,2,3'

_.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
// → logs each number and returns the object (property order is not guaranteed across environments)

underscore: http://underscorejs.org/#each

_.each([1, 2, 3], alert);
=> alerts each number in turn...
Community
  • 1
  • 1
docodemore
  • 1,074
  • 9
  • 19
  • You are welcome, I personally find Amit Joki's answer to be the my favorite (simply because using arguments can be awesome) – docodemore Nov 24 '14 at 15:24
  • You're welcome Greg. If there's anything I can do to explain my answer better let me know. Also, check out a website called codeschool, I learned a ton there and I think it would really help. – docodemore Nov 24 '14 at 16:17
  • Hi docodemore. I’ve put together a simplified [JSFiddle](http://jsfiddle.net/gregabbott/k3uw4cuc/) which might be more helpful in showing what I have and what I’d like to achieve with the code. If it wouldn’t be too much trouble, please could you take a look at it to see if you have any ideas as to how I might be able to get something similar to work. Thank you for the referral to codeschool. I look forward to visiting it. –  Nov 24 '14 at 16:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/65546/discussion-between-greg-and-docodemore). –  Nov 24 '14 at 19:35
3

You don't need an array. Just use arguments

function functionName(){
   for(var i = 0; i < arguments.length; i++){
      // do something with arguments[i];
   }
}

and then you can do

functionName("shot_type","shot_height","shot_angle","framed","scene_depth");

P.S @codebox's solution works if supporting legacy IE version isn't a problem. Don't know why he deleted it...so putting it here so it helps. His answer using forEach

["shot_type","shot_height","shot_angle","framed","scene_depth"].forEach(FunctionName);
Amit Joki
  • 58,320
  • 7
  • 77
  • 95
  • @Amit Thank you. Unfortunately the result is the same. –  Nov 24 '14 at 15:50
  • how are you calling the function? – Amit Joki Nov 24 '14 at 15:51
  • @Amit, if you call a function using your code on an object it will mutate the object itself instead of return a new one. Only in primitives will your code work. This is because objects are passed by reference, and primitives are passed by value. (search javascript pass by reference vs pass by value) – docodemore Nov 24 '14 at 15:54
  • Your code won't work on all types of functions or objects that are passed through: see this http://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language – docodemore Nov 24 '14 at 16:00
1

EDIT: Looking at your Fiddle, you have a return inside the for loop - therefore the function will return after the first iteration. Put the return after the for and concatenate the output to one string.

var output = "";
for(...){
    output += description_of_object + ": " + randomly_selected_item_from_object + ".\n";
}   
// return it
return output;

With Javascript only:

var actions = ["shot_type","shot_height","shot_angle","framed","scene_depth"];
for (var i = 0; i < actions.length; i++){
  FunctionName(actions[i]);
}

With JQuery:

$.each(["shot_type","shot_height","shot_angle","framed","scene_depth"], function(index,value){
  FunctionName(value);
});

I haven't tested it but it should work.

Vanice
  • 676
  • 5
  • 15
1

To avoide redundancy in code use an array with the values, that you want to pass through the function and call the function in an loop.

var vals=["shot_type","shot_height","shot_angle","framed","scene_depth"];
for(var i=0; i<vals.length; i++)
{
    FunctionName(vals[i]);
}

If you want to expand the function (adding another parameter) you can just expand the for-loop and the array structure.

Alternatively you could fill an object with the values and handle this logic in an object. But this would just do a difference on calling the function.

Tim Wißmann
  • 647
  • 6
  • 18
  • Hi Timmy. Thank you very much for your reply. I’ve tried implementing your code but can’t get it to work. Instead of the for-loop running the function on each item in the array, it returns the array content without doing anything to it. Please would you be so kind as to look at this [JSFiddle](http://jsfiddle.net/gregabbott/4hvf33o5/) to see if you can see what is wrong with the way I have implemented your suggestion. Here is a [JSFiddle](http://jsfiddle.net/gregabbott/vpbw44nj/) of the working but redundant code to show the output I’m trying to achieve using the array. Thank you very much! –  Nov 24 '14 at 20:10
  • 1
    I would prefer it, if you think a little bit along. Programming things means always searching for errors...In your working JSFiddle you concat each return value of the function calls in a string variable. Thats not the case in the JSFiddle with my suggestion or in your code example (at your question). So, try to safe your complete string in the `brief` variable, how you did it in your first JSFiddle and pass it through the elements value. Hope I could help ;) – Tim Wißmann Nov 24 '14 at 21:22
  • If my comment helped you, I would like it, if you give me +1 ;) – Tim Wißmann Nov 25 '14 at 12:01