0

I know that javascript functions can take an arbitrary number of arguments which can be accessed via arguments[i]. I'm wondering if it is possible to convert that array into individual arguments to send to another function that also processes a variable list of arguments.

I have the following extension to the string class that basically formats strings similar to how string.format() works in .Net.

String.prototype.format = String.prototype.format = function () {
    var s = this,
        i = arguments.length;

    while (i--) {
        s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
    }
    return s;
};

I have another function that needs to take a javascript object and send properties to be processed into a string. The properties are set by the calling function. Here is an example of the usage I am trying to get. I'm simply stuck at passing the properties through as individual arguments to the function above. Any ideas on how to come about this?

function doMything(){

    var myData = GetMyDataFromSomething(); // returns a javascript array of objects
    var myMessageFormat1 = 'Person with ID {0} name is {1} {2}';
    var myPropertyList1 = ['UserID', 'FirstName', 'LastName']

    var finishedStrings1 = formatTheString(myData, myMessageFormat1, myPropertyList1);
    // ex. Person with ID 45 name is Jake Gyllenhal; Person with ID 46 name is Bob Barker

    var myMessageFormat2 = '{0} is from {1}, {2}';
    var myPropertyList2 = ['FirstName', 'City', 'State']

    var finishedStrings2 = formatTheString(myData, myMessageFormat2, myPropertyList2);
    // ex. Jake is from Phoenix, AZ; Bob is from San Diego, CA
}

function formatTheString(data, formatString, propertyList){
        var myStrings = [];
        data.forEach(function(item){
            myStrings.push(item.format(propertyList)); // this doesn't work because the object is passed as a single argument
        };

        return myStrings.join('; ');
}
3
  • 1
    anotherfunction.apply(context, arguments); --- is this what you want? Commented Jan 7, 2014 at 23:19
  • 1
    "".format will be native soon, i would use a different name... Commented Jan 7, 2014 at 23:20
  • @dandavis good point. I will rename to something like formatText until string formatting is standardized. Commented Jan 8, 2014 at 0:18

4 Answers 4

3

The other answers are correct, but just to explicitly show the arguments chain:

function one() {
    two.apply(this, arguments);
}

function two() {
    console.log(arguments);
}

one("one", "two", "three");

Prints:

["one", "two", "three"]
Sign up to request clarification or add additional context in comments.

Comments

0

Use apply(see MDN):

var yourArguments = ['foo', 'bar'];

formatString.format.apply(formatString, yourArguments);
// equivalent to 'formatString.format('foo', 'bar')

So, your function could be:

function formatTheString(data, formatString, propertyList){
        var myStrings = [];
        data.forEach(function(item){
            myStrings.push(item.format.apply(item, propertyList));
        };

        return myStrings.join('; ');
}

Comments

0

Sure. Use apply()

   var args = ['arg1', 'arg2'];
   fn.apply(this, args);

is equivalent to

   fn('arg1', 'arg2');

1 Comment

Not sure why this was down-voted, my guess is that it's because the two are not technically equivalent. Using apply lets you specify the this context, which here you have set to the callers this. However, the invocation of a function from scope (versus from a property of an object) will have this pointing to window (the global object).
0

I just wanted to add this as my final working solution in hopes that it will help someone. There were some logical errors on my original thought in the OP.

var MyClass = {

    loadSupportArticles: function() {
            var itemMarkupFormat = '<tr class="row-link single-cell"><td><a href="support-page.html/{0}">{1}</a></tr>';
            var $supportAriclesList = $('#support-panel tbody');

            this.populateTableFromAjaxResult(
                '/support/Popular',
                $supportAriclesList,
                itemMarkupFormat,
                ['ArticleId', 'Title']);
        },

    loadUsers: function() {
            var itemMarkupFormat = '<tr class="row-link"><td><a href="edit-user.html/{0}">{1}</a></td><td>{2}</td></tr>';
            var $userSummaryList = $('#users-panel tbody');

            this.populateTableFromAjaxResult(
                '/accountuser/AccountUsersAsync',
                $userSummaryList,
                itemMarkupFormat,
                ['Id', 'Name', 'Type']);
        },

    // the part you guys helped with
    getListItems: function(data, formatString, propertyNames) {
        var completeList = [];

        // for each data item
        for (var i = 0; i < data.length; i++) {

            // get values for each argument
            var args = [];
            for (var j = 0; j < propertyNames.length; j++) {
                var propertyName = propertyNames[j];
                args.push(data[i][propertyName]); // e.g.  data[0]["PropName"]
            }

            // apply the template
            completeList.push(formatString.format.apply(formatString, args));
        }

        return completeList.join('');
    },

    populateTableFromAjaxResult: function(url, $target, formatString, propertyNames) {
        $target.empty();

        $.ajax({
            url: url,
            type: 'GET',
            accept: 'application/json',
            success: function(data) {
                var formattedData = MyClass.getListItems(data, formatString, propertyNames);
                $target.append(formattedData);
            }
        });
    }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.