JavaScript Snippet – Simple Stack Trace In Chrome

Often times in JS it is necessary to trace through someone else’s code (or your own ;-) ) to determine the root of a problem. Many times I have found that knowing how a function was called in the first place can be very helpful. Since I use Chrome for development, as i’m sure many others do, I thought it appropriate to point out that you can show the stack trace whenever you want in the console by adding the following snippet to your code:

console.log('Stack trace:', (new Error).stack);

For those who need similar functionality in other browsers, I did a quick Google search and found stacktrace.js. Happy coding! 8-)

Excel – Multi-column VLookup

When analyzing data in Excel at times it is necessary to pull data from another data source based on more than one column. In this case you can use the MATCH function in an array formula. Just so you understand the general idea of an array, it is a collection of values. The match function is generally used to find a value in an array. Knowing this, we will use this Excel file to show how to engineer a multi-column VLOOKUP in a few simple steps.

Source Data Tab

Above is a screenshot of the data in the Source Data tab. On our Lookups tab I started off with just the first names and last names of some users. In order to pull the corresponding usernames and DOBs (dates of birth) I did the following:

  1. Setup a column indicating where the matching data was found by using the following array formula:
    {=MATCH(1,('Source Data'!$A$2:$A$27=$A1)*('Source Data'!$B$2:$B$27=$B1),0)}

    • It is important to note that even though the formula is surrounded by curly braces, those are put there by Excel (NOT MANUALLY) when executing the formula by using the CTRL+SHIFT+ENTER key combination.
    • The first parameter (1) indicates the value being searched for in the second parameter.
    • The second parameter is an array which remains such only because of the CTRL+SHIFT+ENTER key combination used to finalize the formula.

      • That will produce an array of 0s and 1s which are coerced into the numbers because of the multiplication operation.
      • If there was only one column checked and the multiplication were taken out, the array will be full of TRUEs and FALSEs. For example the formula=TRUE*TRUE results in 1 while TRUE*FALSE results in 0.
    • The third parameter 0 indicates that the first parameter must match be an exact match of one of the items in the array (second parameter).
    • The value returned will be the position (start at 1) of the value in the array if found. If not found an N/A error will be returned.
  2. Setup a new column which references the matching row column to pull the corresponding username if a matching row was found. If the row wasn’t found show the cell as empty:
    =IF(ISNA($C2),"",INDEX('Source Data'!$C$2:$C$27,$C2))
  3. Setup a new column which references the matching row column to pull the corresponding DOB if a matching row was found. Format the date using the YYYY-MM-DD format. If the row wasn’t found show the cell as empty:
    =IF(ISNA($C2),"",TEXT(INDEX('Source Data'!$D$2:$D$27,$C2),"YYYY-MM-DD"))

After doing the above three steps in row 2 of the Lookups sheet and copying the formulas down, the final result was this:

Lookups Tab

If I were to clean this up a bit more I might hide column C of the Lookups tab, but other than that there really isn’t much else you need to do. I know this may still seem a bit mysterious, but with practice you will begin to understand array formulas better and perhaps write other useful array formulas to get the job done. For all of you who came to figure out how to do a multi-criteria lookup, I hoped it helped but if not, comment on what needs clarifying and I will do my best to help. 8-)

JavaScript – Creating Classes

As many people know, JavaScript doesn’t really have classes but you can mimic some of their behavior with the prototypal setup available in JavaScript. Still, a lot of times it is just easier when you have a function that does most of the work for you. For that reason, I wrote the classify:

/**
 * @license JS Classify - By Chris West - MIT License
 */
/**
 * Creates a class using the specified constructor and options.
 * @param  {!Function} constructor  The constructor function.
 * @param  {{ privateKey:string, setters:Array<string>, getters:Array<=string>, prototype:Object<!Function>, properties:Object, superClass:Function }} options
 *     Object containing the class options.  The privateKey is the name of the
 *     privateKey that will be assigned to every instance.  The setters array
 *     contains names of private data members for which setters will be setup.
 *     The getters array contains names of private data members for which
 *     getters will be setup.  The prototype object will contain the prototype
 *     values that will be attached to the class' prototype.  The superClass
 *     is the function that will act as the class' super class and all
 *     prototypes will be inherited from it.
 * @return {!Function}  The newly created class.
 */
var classify = (function(emptyObject, fakeClass, global, undefined) {
  var hasOwnProperty = emptyObject.hasOwnProperty;
  var typeOf = function(o, p) {
    o = o === global
      ? "global"
      : o == undefined
        ? o === undefined
          ? "undefined"
          : "null"
        : emptyObject.toString.call(o).slice(8, -1);
    return p ? p === o : o;
  };

  function camelCase(str, delim) {
    delim = delim || ' ';
    var pos;
    while ((pos = str.indexOf(delim)) + 1) {
      str = str.slice(0, pos) + str.charAt(pos + 1).toUpperCase() + str.slice(pos + 2);
    }
    return str;
  }

  /**
   * Setup inheritance.
   * @param {!Function} baseClass  The base class from which the subclass
   *     inherits its prototypal values.
   * @param {!Function} subClass  Class which inherits from the base class.
   * @return {!Function}  The updated subclass.
   */
  function inherit(baseClass, subClass) {
    fakeClass.prototype = baseClass.prototype;
    var prototype = subClass.prototype = new fakeClass();
    prototype.superClass = baseClass;
    return prototype.constructor = subClass;
  }

  // Return classify function.
  return function(constructor, options) {
    var outerPrivateData;

    var privateKey = options.privateKey || '_';

    var realConstructor = function() {
      this[privateKey] = properties && hasOwnProperty.call(properties, privateKey)
        ? properties[privateKey]
        : {};
      return constructor.apply(this, arguments);
    };

    // If the super-class is defined use it.
    var superClass = options.superClass;
    if (superClass) {
      realConstructor = inherit(superClass, realConstructor);
    }

    // Add class level properties.
    var properties = options.properties;
    if (properties) {
      for (var key in properties) {
        realConstructor[key] = properties[key];
      }
    }

    var realPrototype = realConstructor.prototype;
    var myPrototype = options.prototype || {};

    // Add getters.
    var getters = options.getters || [];
    for (var i = 0, len = getters.length; i < len; i++) {
      (function(name) {
        myPrototype[camelCase('get_' + name, '_')] = function() {
          return this[privateKey][name];
        };
      })(getters[i]);
    }

    // Add setters.
    var setters = options.setters || [];
    for (var i = 0, len = setters.length; i < len; i++) {
      (function(name) {
        myPrototype[camelCase('set_' + name, '_')] = function(newValue) {
          var privateData = this[privateKey];
          var oldValue = privateData[name];
          privateData[name] = newValue;
          return oldValue;
        };
      })(setters[i]);
    }

    // Add all prototypal values.
    for (var key in myPrototype) {
      realPrototype[key] = myPrototype[key];
    }

    return realConstructor;
  }
})({}, function(){}, this);

How To Use classify()

The first parameter that you pass should be the constructor. The second parameter will be an object containing properties representing any options you want to add to the class:

  • privateKey - string
    Defaults to "_". The property name for the object which will house all of the private data for each class instance.
  • getters - Array
    An array of strings indicating the getters that should be automatically setup to retrieve the private data members with the same name. These names will be camel-cased based on underscore characters.
  • setters - Array
    An array of strings indicating the setters that should be automatically setup to set the private data members with the same name. These names will be camel-cased based on underscore characters. All setters return the previous value.
  • properties - Object
    An object containing all of the properties that will be added to the class object.
  • prototype - Object
    An object containing all of the values that should be added to the prototype of the class.
  • superClass - Function
    The super-class from which this new class will inherit. This will overwrite the superClass property of the class' prototype.

Example Classes

The following exemplifies how easy it is to create classes with classify():

// Create a simple base class.
Being = classify(
  function (species) {
    this._.species = species;
  },
  { getters: ['species'] }
);

// Create a more complex sub-class.
Human = classify(
  function (firstName, lastName) {
    this.superClass.call(this, 'Human');
    this._.firstName = firstName;
    this._.lastName = lastName;
  },
  {
    getters: [ 'firstName', 'lastName' ],
    setters: [ 'firstName' ],
    prototype: {
      toString: function() {
        return this.getFullName() + ' (' + this._.species + ')';
      },
      getFullName: function() {
        return this._.firstName + ' ' + this._.lastName;
      }
    },
    superClass: Being
  }
);

The first class that I created above is a Being class which just has one private member: species. The Being.prototype.getSpecies() function is defined for this class as well. The second class is the Human class which is a sub-class of the Being class. The species defaults to "human" while two more private members are included: firstName and lastName. There are getters for all of the private members but there is only one setter which is for the firstName. Additionally the Human.prototype.toString() and Human.prototype.getFullName() functions have been defined to provide additional features to the class.

Try Me!

The above example shows (as long as you are using a modern browser) how these newly created functions work. There is more you can do with this of course so if you want go ahead and play with the above example or copy the classify code and create your own classes. Happy coding! 8-)

JavaScript Snippet – Undo Camel Case

Probably due to it being so late, I was looking for code to uncamelize (undo camel-casing) any string. I came across what claimed to be a solution in PHP but unfortunately did nothing but lowercased my string. Therefore I decided to write my own solution:

function uncamelize(s) {
  return s.replace(/[A-Z]/g, '_$&').toLowerCase();
}

Believe it or not, the solution is that simple. Here is an example of using it:

An interesting thing to note about this uncamelize implementation is that it uses the $& pattern to reuse the substring matched by the regular expression. Even though this substring is commonly used it is documented as shown here.

PHP – Foreach By Reference

Today I was writing some code in which I wanted to modify the values of an array within a for-loop. The obvious solution would be to use the key to modify the value but there is actually another way of doing it:

$arr = array(1,2,3,4,5);
foreach ($arr as &$value) {
  $value = $value * $value;
}
print_r($arr);

The above code will actually go through the array of integers 1 to 5 and change the array to be the squares of those values. The output is as follows:

Array
(
    [0] => 1
    [1] => 4
    [2] => 9
    [3] => 16
    [4] => 25
)

This works because placing the ampersand in front of the $value makes the variable refer to the actual value within the array and updating it will update the value within the array.

JavaScript – Getting All Text Nodes

I have been working on something I am calling JS-Proofs (or jPaq Proofs). While working on the menu I was faced with the annoying issue of either not having whitespaces between my elements in the markup or removing them some other way. Since my favorite language is JS, I decided to write a function that would remove all of the text nodes with whitespaces for me. This evolved into a more general function which retrieves an array of all the text nodes contained by a given element:

/**
 * Gets an array of the matching text nodes contained by the specified element.
 * @param  {!Element} elem
 *     The DOM element which will be traversed.
 * @param  {function(!Node,!Element):boolean} opt_fnFilter
 *     Optional function that if a true-ish value is returned will cause the
 *     text node in question to be added to the array to be returned from
 *     getTextNodesIn().  The first argument passed will be the text node in
 *     question while the second will be the parent of the text node.
 * @return {!Array.}
 *     Array of the matching text nodes contained by the specified element.
 */
function getTextNodesIn(elem, opt_fnFilter) {
  var textNodes = [];
  if (elem) {
    for (var nodes = elem.childNodes, i = nodes.length; i--;) {
      var node = nodes[i], nodeType = node.nodeType;
      if (nodeType == 3) {
        if (!opt_fnFilter || opt_fnFilter(node, elem)) {
          textNodes.push(node);
        }
      }
      else if (nodeType == 1 || nodeType == 9 || nodeType == 11) {
        textNodes = textNodes.concat(getTextNodesIn(node, opt_fnFilter));
      }
    }
  }
  return textNodes;
}

What is kind of cool about the above function is that it not only allows you to get all of the child text nodes, but all descendant text nodes. This function also provides the capability of specifying an optional filtering function to just return text nodes that match a criteria. The function will be passed the text node in question and the parent of that text node. In order to specify that the text node should be added to the array returned from getTextNodesIn you must return a true-ish value.

The following is an example of how to use this function in order to remove all whitespace text nodes from an element:

var menu = document.getElementById('divMenu');
getTextNodesIn(menu, function(textNode, parent) {
  if (/^\s+$/.test(textNode.nodeValue)) {
    parent.removeChild(textNode);
  }
});

In the strictest sense I am actually kind of hacking the new function that I defined but it gets the job done. 8-)

JavaScript – Parsing A Number

If you should ever need to parse a number into an array of bits or a different base you can use the following function:

var splitNumber = (function(MAX) {
  for (; MAX + 1 - MAX == 1; MAX *= 2){}
  return function (num, radix) {
    // Validate num
    num = parseInt(num, 10);
    if (!isFinite(num) || 0 > num || num > MAX) {
      throw new Error('splitNumber() num argument must be a non-negative finite number less than ' + MAX);
    }
 
    // Validate radix
    radix = parseInt(radix || 10, 10);
    if (!(1 < radix && radix <= MAX)) {  // Also prevents NaN
      throw new Error('splitNumber() radix argument must be greater than 2 and less than ' + MAX);
    }
 
    return num.toString(radix).split('');
  };
})(1 << 30);

Here is an example of the tests and outputs:

I want to thank ildar for contributing the refinement of this function. 8-)

JavaScript Snippet – Is This In An IFRAME?

Recently I had to determine when my code is running in an iframe. In order to do this many would simply use this code:

var isInIframe = window.top == window.self;

Unfortunately, if you are writing code that can potentially be added to any page (even those whose code isn’t fully controlled by you), you may experience an unexpected result when someone decides to write to window.self. Truthfully, it does seem strange to even write a variable called self in the global namespace, but at Monetate we have run into this issue before. For this reason, it may be a better idea to simplify the test even further by doing the following:

var isInIframe = window.top == window;

As far as I can tell, there isn’t a reason why this wouldn’t work, but perhaps you have found an instance in which this would fail. If so, please let me know, but as for now I think this simple solution should indicate whether or not the window is the top-most window. 8-)

JavaScript – Faking Native Functions

The other day I kind of just wanted a reason to write a Gist and embed it on my site using this method. What I came up with was a quick way to make all functions appear to be native:

Here is an example of what happens:

function alertAndReturn() {
  alert.apply(this, arguments);
  return arguments;
}

alert(alertAndReturn); // function alertAndReturn() { [native code] }
alert(function(){});   // function () { [native code] }

I have no clue when this would be useful in the real world but if you need it, here it is! 8-)

EcmaScript 6 – String.prototype.repeat()

One simple function that is on the roster to be released in EcmaScript 6 is String.prototype.repeat. The following can be used to define it in browsers which don’t currently have it defined natively:

String.prototype.repeat = String.prototype.repeat || function(count) {
    return Array(count >= 0 ? parseInt(count, 10) + 1 : -1).join(this);
};

Here are some examples of using this function (modified from the originals found on MDN):

alert("->".repeat(-1));     // RangeError
alert("->".repeat(0));      // ""
alert("->".repeat(1));      // "->"
alert("->".repeat(2));      // "->->"
alert("->".repeat(3.6));    // "->->->" (count will be converted to integer)
alert("->".repeat(1/0));    // RangeError

There is more information about this new JavaScript function here.

JavaScript, Math, and much more.