JavaScript – Passing Arguments By Name

One thing that I think would be cool is if JavaScript provided a way to pass arguments to a function by name. About two years ago I wrote the code for a Function.prototype.invoke but never released it as part of jPaq like I had hoped. Recently, I decided to re-use the code I wrote and improve it. The following defines a Function.prototype.index function which enables parameter passing by name:

/**
 * @license Copyright 2013 - Chris West - MIT Licensed
 */
(function(reComments, reParams, reNames) {
  Function.prototype.index = function(arrParamNames) {
    var fnMe = this;
    arrParamNames = arrParamNames
      || (((fnMe + '').replace(reComments, '')
           .match(reParams)[1] || '')
          .match(reNames) || []);
    return function(namedArgs) {
      var args = [], i = arrParamNames.length;
      args[i] = namedArgs;
      while(i--) {
        args[i] = namedArgs[arrParamNames[i]];
      }
      return fnMe.apply(this, args);
    };
  };
})(
  /\/\*[\s\S]*?\*\/|\/\/.*?[\r\n]/g,
  /\(([\s\S]*?)\)/,
  /[$\w]+/g
);

Now let’s look at an example of using this code. Let’s define a function which accepts four parameters and prints the value of each parameter to the console:

var showA2D = (function(a, b, c, d) {
  console.log('a = ', a);
  console.log('b = ', b);
  console.log('c = ', c);
  console.log('d = ', d);
}).index();

Now we have our function and believe it or not but all we had to do was surround the function definition in parentheses and calls its index function to make it accept parameters by name. Now let’s call the function with some arguments:

showA2D({
  a: "first parameter",
  d: "last parameter",
  b: "second parameter"
});

Executing the above will print the following in the console:

a =  first parameter
b =  second parameter
c =  undefined
d =  last parameter

Another interesting thing we could have done when we defined showA2D was actually define the mapping of the parameters. This is especially useful if you plan on minifying the function which will be indexed. The following shows how we can map the arguments:

// Define the function.
var showA2D = (function(a, b, c, d, args) {
  console.log('a = ', a);
  console.log('b = ', b);
  console.log('c = ', c);
  console.log('d = ', d);
  console.log('args = ', args);
}).index(['a', 'b', 'c', 'd']);

// Call the new function.
showA2D({
  a: "first parameter",
  d: "last parameter",
  c: "third parameter"
});

After running the above code something like the following will be shown in the console:

a =  first parameter
b =  undefined
c =  third parameter
d =  last parameter
args =  Object {a: "first parameter", d: "last parameter", c: "third parameter"}

As you may have determined the Function#index function takes an optional Array which should contain the names of the parameters which will be mapped to the function. Another thing that is important to note is that the object that is passed to the indexed function will be passed to the original function as the final parameter.

If I ever get around to publishing the next version of jPaq this will probably make its way into the codebase. Until then, feel free to use this version (just give me some credit ;) ).

JavaScript – Unicode Escape Sequence Function

A few days ago someone asked me how I would go about determining the unicode escape sequence for an arbitrary character. Of course, I went to Google Chrome’s web console and showed them how it can be done by using the charCodeAt, toString, and slice functions. The following is a function which will take in a string and return the equivalent with all characters converted to their unicode escape sequence:

/**
 * Replaces each character in the string with the corresponding
 * unicode escape sequence.
 * @param {string} str  The string of characters to escape.
 * @return {string}  The string with the escape sequences.
 */
function toUnicodeSequence(str) {
  for(var i = str.length; i--;) {
    str = str.slice(0, i) + '\\u'
        + ('000' + str.charCodeAt(i).toString(16)).slice(-4)
        + str.slice(i + 1);
  }
  return str;
}

Let’s review some basic JavaScript functionality:

  • The String.prototype.charCodeAt function basically provides the ability to find the integer equivalent of any one character within a string.
  • The Number.prototype.toString function provides the ability to convert the number into a string which represents that number in a different base. In otherwords, (5).toString(2) will result in 101 because binary (from the 2 passed in) version of 5 is 101.
  • The String.prototype.slice function is similar to String.prototype.substring function but it has one advantage: you can pass in negative parameters as well. If you pass in a negative number, the index will be calculated from the end of the string instead of the beginning. Therefore executing ("JavaScript").slice(-6) results in "Script" because those are the last 6 characters of the string "JavaScript".
  • By using these three functions together, we can create a function such as toUnicodeSequence which will return the escape sequences for all of the characters. I am not sure how often one would need such a function but have fun with it. 8)

JavaScript – Prototypes, Private Data, & Safe Factories

So, after doing even more research on providing prototypal functions access to private data, I came across this article on the Safe Factory Pattern. It is actually similar to my Accessor Verification pattern that I recommended here on Monday. The quick summary is that by shortening this a bit, you can actually safely achieve private data access from prototypal functions:

(function(global, returnData, undefined) {
  // Variable returnData is for temporarily storing what
  // will be returned from the openMySafe function.
  // "undefined" is defined this way so that to minify it
  // in closure compiler.
  
  // Gets the private data from the safe that was created
  // and returns it.
  function openMySafe(me) {
    returnData = undefined;
    me._();
    return returnData;
  }

  // Determine if caller is a property when a function is
  // executed.
  function callerExists() {
    return !!callerExists.caller;
  }
  callerExists = callerExists();
  
  // Returns a function that will return the provided
  // private data only when returnData evaluates to true.
  function makeMySafe(privateData) {
    function safe() {
      // If the caller of this function is openMySafe,
      // assign privateData to returnData.
      if(callerExists == (safe.caller == openMySafe)) {
        returnData = privateData;
      }
    };
    return safe;
  }
  
  // Create the Person class in the global namespace.
  var PersonPrototype = (global.Person = function(firstName, lastName) {
    this._ = makeMySafe({
      firstName : firstName,
      lastName : lastName
    });
  }).prototype;
  PersonPrototype.getName = function() {
    var pData = openMySafe(this);
    return pData.firstName + ' ' + pData.lastName;
  };
  PersonPrototype.setFirstName = function(firstName) {
    var pData = openMySafe(this);
    pData.firstName = firstName;
    return this;
  };
  PersonPrototype.setLastName = function(lastName) {
    var pData = openMySafe(this);
    pData.lastName = lastName;
    return this;
  };
})(this);

// Test out the code.
var chris = new Person('Chris', 'West');
alert(chris.setFirstName('C.').setLastName('Webber').getName());

// Make sure the private data is not accessible.
var prefix = chris._() === undefined ? 'un' : '';
// Outputs:  "The private data returned is undefined."
alert('The private data returned is ' + prefix + 'defined.');

This Abbreviated Safe Factory Pattern works for the following reasons:

  • The makeMySafe({private_data}) function takes the private data associative array object and uses encapsulation to return a function (safe function) which can assign the value to be returned by a safe opener function.
  • JavaScript is only arguably single-threaded (web-workers and browser events may be the exception but this doesn’t seem to be explicitly stated); no two threads can run at the same time.
  • Since JavaScript is single-threaded (or at least one function should execute fully before another starts), we can rely on one control value to determine when private data can be returned by the safe functions.
  • The openMySafe({person_object}) function…
    1. takes a person object
    2. sets returnData to undefined
    3. calls the safe function produced by makeMySafe({private_data}) (AKA {person_object}._()) to assign the private data object to returnData
    4. returns the value of returnData which should be the private data object

I actually had to add an if statement to the safe function due to the existence of Function.prototype.caller. Without this if statement, rogue code could get a reference to openMySafe which would effectively provide access to the private data of an object. This is actually a deficiency that even exists in the original Safe Factory Pattern

If multiple threads could run at once it would be possible for the incorrect private data to get passed back to the wrong class instance. If you do have to allow your classes to multi-threaded, I would recommend using the Accessor Verification Pattern I suggested in this post.

Again, I invite all JavaScripters to try to find a way to get the private data without modifying the closure. I am personally convinced that using this Abbreviated Safe Factory Pattern is a fullproof way of allowing prototypal functions access to truly private members. If you can find a way to disprove me, though, I would be thoroughly impressed (and would much appreciate it)! 8)

JavaScript – Prototypal Functions & Private Data

A while back many people responded to this post, helping me see that my solution for providing private data access to prototypal functions was incomplete. Since then, I had been playing around with some possible solutions in my head and finally came up with two:

  1. Prototypal Registry
  2. Accessor Verification

Prototypal Registry

Prototypal Registry involves using an associative array of all of the original prototypal functions to make sure that the function that is calling the private data accessor function is authentic. The following source code is an example of a Person class which implements this solution to allow three prototypal functions access to private data:

(function(global) {
  // Get generic hasOwnProperty function just in case it is overwritten.
  var hasOwnProperty = ({}).hasOwnProperty;
  
  // Adds the properties defined in objWithExtensions to objToExtend.
  function extend(objToExtend, objWithExtensions) {
    for(var key in objWithExtensions) {
      if(hasOwnProperty.call(objWithExtensions, key)) {
        objToExtend[key] = objWithExtensions[key];
      }
    }
  }
  
  // Creates a Person class.
  var PersonRegistry = {
    getName : function() {
      var pData = this._('getName');
      return pData.firstName + ' ' + pData.lastName;
    },
    setFirstName : function(firstName) {
      var pData = this._('setFirstName');
      pData.firstName = firstName;
      return this;
    },
    setLastName : function(lastName) {
      var pData = this._('setLastName');
      pData.lastName = lastName;
      return this;
    }
  };
  extend((global.Person = function(firstName, lastName) {
    var pData = {
      firstName : firstName,
      lastName : lastName
    };
    function _(name) {
      return PersonRegistry[name] == _.caller && pData;
    }
    this._ = _;
  }).prototype, PersonRegistry);
})(this);

var chris = new Person('Chris', 'West');
alert(chris.setFirstName('Christopher').setLastName('Webber').getName());

The problem with this first solution is the fact that it cannot be guaranteed to work in all environments. Strict mode, Opera 10, BESEN and Rhino 1.7 don’t support the function “caller” property (better breakdown), thusly preventing this solution from working in those environments. Due to this issue, I started thinking about a different solution.

Accessor Verification

The true issue with my original solution (from this post and this post) was the fact that you could override the private data accessor and steal the secret key that was used by all other private data accessors. This then would give that rogue code access to the private data of instances of all such classes. Accessor Verification prevents rogue outside code from being able to do that. Using this scripting pattern, you create a function which is called to then verify that the private data accessor function hasn’t been tampered with. After the accessor function is verified, it is then called with the secret key (accessible only by code within the closure) to get access to the private data. The following source code is an example of a Person class which implements this solution to allow three prototypal functions access to private data:

(function(key, global) {
  // Creates a private data accessor function.
  function _(pData) {
    return function(aKey) {
      return aKey === key && pData;
    };
  }
  
  // Private data accessor verifier.  Verifies by making sure that the string
  // version of the function looks normal and that the toString function hasn't
  // been modified.  NOTE:  Verification can be duped if the rogue code replaces
  // Function.prototype.toString before this closure executes.
  function $(me) {
    if(me._ + '' == _asString && me._.toString === _toString) {
      return me._(key);
    }
  }
  var _asString = _({}) + '', _toString = _.toString;
  
  // Creates a Person class.
  var PersonPrototype = (global.Person = function(firstName, lastName) {
    this._ = _({
      firstName : firstName,
      lastName : lastName
    });
  }).prototype;
  PersonPrototype.getName = function() {
    var pData = $(this);
    return pData.firstName + ' ' + pData.lastName;
  };
  PersonPrototype.setFirstName = function(firstName) {
    var pData = $(this);
    pData.firstName = firstName;
    return this;
  };
  PersonPrototype.setLastName = function(lastName) {
    var pData = $(this);
    pData.lastName = lastName;
    return this;
  };
})({}, this);

var chris = new Person('Chris', 'West');
alert(chris.setFirstName('Christopher').setLastName('Webber').getName());

The above solution should work in all JavaScript/JScript environments. If the private accessor function is overriden, the call by any prototypal function will fail because the verification function will notice that it has been tampered with and undefined will be returned to the prototypal function as the private data container. Neither by using the previous line of thinking (suggested by Esailija), nor by using any other have I been able to extract private data without modifying the original code (that which appears in the closure). The only time when rogue code could dupe the verifier function is if the rogue code overrides Function.prototype.toString before the closure defining the classes is executed. In that case, though, you may have more issues than just those encountered with your private data becoming public. :D

I would be interested in seeing if any readers can find a way to get access to the private data object with code that runs after the class is defined. If you are good at JavaScript, and think you can figure it out, let me know, but I believe this is a rock solid solution. 8) Happy hacking!!!

JavaScript – Date Difference Function

A few months ago I wrote a blog post about extensions to the Date.prototype. That post provided ways to add date parts and subtract date parts. Today’s post shows you how to use a generic Date.prototype.diff() function to find the difference between two dates and optionally return a string specifying the difference. This can be particularly useful if you need to show a countdown until a certain time.

The following is the code that I wrote for a comprehensive date difference function:

// Date.prototype.diff() - By Chris West - MIT Licensed
(function() {
  var SEC = 1e3,
      MIN = 6e4,
      HOUR = 36e5,
      DAY = 864e5,
      WEEK = 6048e5,
      reFormat = /'(''|[^']+)*'|\{([^}\\]+|\\[\s\S])+(?!\\)\}|-?([WY])\3*|-?([SsmhdDM])\4*%?|<[12]:(\w+)(?::(0+))?>/g,
      reSlashChars = /\\(.)/g,
      reStartComma = /^,/,
      reType = /\w%?$/,
      reSplit = /,(\\[\s\S]|[^\\,]+)*/g,
      reWords = /\W/g;
  Date.prototype.diff = function(endDate, format) {
    var me = new Date(Math.min(this, endDate));
    endDate = new Date(Math.max(this, endDate));
    var type,
        neg = +me != +this ? -1 : 1,
        diff = endDate - me,
        types = {
          S : diff,
          "S%" : diff % SEC,
          s : type = parseInt(diff / SEC),
          "s%" : type % 60,
          m : type = parseInt(diff / MIN),
          "m%" : type % 60,
          h : type = parseInt(diff / HOUR),
          "h%" : type % 24,
          d : type = parseInt(diff / DAY),
          "d%" : type % 7,
          D : type,
          "D%" : (type = endDate.getDate() - me.getDate()) < 0 ? endDate.getDate() + parseInt((new Date(me.getFullYear(), me.getMonth() + 1, 1) - me) / DAY) : type,
          W : parseInt(diff / WEEK),
          M : type = 12 * (endDate.getFullYear() - me.getFullYear()) + endDate.getMonth() - me.getMonth() - (endDate.getDate() < me.getDate()),
          "M%" : type % 12,
          Y : parseInt(type / 12)
        };
    if(neg < 0) {
      for(var i in types) {
        types[i] *= -1;
      }
    }
    types["-"] = neg > 0;
    return format
      ? format.replace(reFormat, function(match, index, $2, $3, $4, datePart, datePartLength) {
        if(match.charAt(0) == "'") {
          return match.slice(1, -1);
        }
        if(datePart) {
          index = match.charAt(1) == "1" ? me : endDate;
          try {
            return padNum(index["get" + datePart]() + (datePart == "Month" ? 1 : 0), (datePartLength || "").length);
          }
          catch(e) {
            return match;
          }
        }
        if(match.charAt(0) == "{") {
          index = [];
          ("," + match.slice(1, -1)).replace(reSplit, function(a) {
            index.push(a.slice(1));
          });
          console.log(index);
          if(index[2] in types) {
            type = types[index[2]];
          }
          return (index[+!(Math.abs(type) - 1)] || "").replace(reSlashChars, "$1");
        }
        type = types[match.match(reType)[0]];
        index = (type < 0 && match.charAt(0) != "-" ? -1 : 1) * type + "";
        match = match.replace(reWords, "");
        return padNum(index, match.length);
      })
      : types;
  };

  function padNum(num, digits) {
    var neg = (num = num + "").indexOf("-") == 0;
    return (neg ? "-" : "") + (new Array(Math.max(digits - (num).length + 1 + neg, 1))).join(0) + num.replace("-", "");
  }
})();

Let’s say that we have an SPAN element whose id attribute is countdown. If we wanted a countdown until the end of the year to show up in that element, we could write something like the following:

setInterval(function() {
  var now = new Date,
      nextYear = new Date(now.getFullYear() + 1 + "/01/01"),
      format = "M 'month'{s}, D% 'day'{s}, h% 'hour'{s}, m% 'minute'{s}, s% 'second'{s}";
      span = document.getElementById("countdown");
  span.innerHTML = now.diff(nextYear, format);
}, 1000);

The following JSBin example gives you the ability to experiment with the format string:
JS Bin

The following are more example date differences and format strings that could be used:

alert(new Date("2012/11/08 14:17:00").diff(new Date, "D:hh%:mm%:ss%:SSS%"));
alert(new Date("2012/10/09 14:17:00").diff(new Date, "D 'day'{s}, h% 'hour'{s}, m% 'minute'{s}, s%.SSS% 'seconds'"));
alert(new Date("2012/10/09 14:17:00").diff(new Date, "D 'día'{s}, h% 'hora'{s}, m% 'minuto'{s}, s% 'segundo'{s}"));

String Literals

In order to use string literals in a format string, you must surround your string in single quotes. In order to escape the single, simply prepend it with another single quote.

Date Difference Measurements

There are two different measurements for date differences: full measurements and remainder measurements. All remainder measurements are suffixed by percent signs following the meta characters. The following is a table of all of the date difference meta characters and the corresponding measurements:

Meta Character(s) Measurement
Y The amount of full years between the two dates.
W The amount of full weeks between the two dates.
M The amount of total months between the two dates.
M% The amount of months remaining, not including those counted in the total amount of years between the two dates.
D The amount of total days between the two dates.
D% The amount of days remaining, not including those counted in the total amount of months between the two dates.
d The amount of total days between the two dates. The same as D.
d% The amount of days remaining, not including those counted in the total amount of weeks between the two dates.
h The amount of total hours between the two dates.
h% The amount of hours remaining, not including those counted in the total amount of days between the two dates.
m The amount of total minutes between the two dates.
m% The amount of minutes remaining, not including those counted in the total amount of hours between the two dates.
s The amount of total seconds between the two dates.
s% The amount of seconds remaining, not including those counted in the total amount of minutes between the two dates.
S The amount of total milliseconds between the two dates.
s% The amount of milliseconds remaining, not including those counted in the total amount of seconds between the two dates.

Padding Measurements with Zeroes

You can pad a measurement with leading zeroes if too short. In order to make sure that a non-remainder measurement has at least two digits, you can simply append the same meta character to the end of itself. The amount of times that a meta character appears next to itself will determine the minimum number of digits to display. The following are examples:

  • hh – two digits for the total amount of hours
  • mm – two digits for the total amount of minutes
  • ss – two digits for the total amount of seconds
  • SSS – three digits for the total amount of milliseconds

In order to make sure that remainder measurements are padded, you can use the same principle. Only duplicate the first character of the meta character and prepend it as many times as you want. The amount of times that a meta character appears (not including the percent sign) determines the minimum number of digits to display. The following are examples:

  • hh% – two digits for the amount of hours (excluding those counted in the amount of days)
  • mm% – two digits for the amount of minutes (excluding those counted in the amount of hours)
  • ss% – two digits for the amount of seconds (excluding those counted in the amount of minutes)
  • SSS% – three digits for the amount of milliseconds (excluding those counted in the amount of seconds)

Negative Measurements

By default, negative numbers will not be shown. In order to show them, you will need to prefix the meta character string with a negative sign.

Conditional Literal Strings (1-based)

To specify which strings will appear if the meta character was 1 or not 1 you will have to use following format: {DISPLAY_IF_ONE,DISPLAY_IF_NOT_ONE,META_CHARACTER}.

Section Optional Description
DISPLAY_IF_ONE No The string to display if the meta character is 1
DISPLAY_IF_NOT_ONE Yes The string to display if the meta character is NOT 1.
META_CHARACTER Yes The singular meta character that will be used as the conditional to determine which of the two preceding strings to display. If not given, this will default to the most recently seen meta character in the entire format string.

Escaping Special Characters In Conditional Literal Strings

If you want a special character such as a comma or a curly bracket to display, you will need to prefix it with a backslash character.