Tag Archives: Function

JavaScript – Function.prototype.getCall()

As I was writing jPaq v2.0, one of the things I wanted in quite a few cases were functions in which the this object could be parameterized without using the theFunction.apply() function or the theFunction.call(). Here is an example of what is often done with native prototypal functions:

// Reference the generic Object's prototypal function:
var toString = Object.prototype.toString;

// Use the toString function on different things:
alert(toString.call(3.14159265));  // [object Number]
alert(toString.call(/regular_expression/g)); // [object RegExp]
alert(toString.call("a string")); // [object String]
alert(toString.call(toString)); // [object Function]

// Reference the Array's prototypal function.
var slice = Array.prototype.slice;

// Use the slice function on different things:
alert(slice.call([0,1,2,3], 2));  // 2,3
alert(slice.call("abcd", 1));  // b,c,d
alert(slice.call((function(){return arguments})(9,8,7), 0));  // 9,8,7

Even though, we now have a reference to the toString() and slice() functions, we’ll always need to use the call() function or apply() function to define this. Personally, I would much prefer something like this:

// Reference the generic Object's prototypal function:
var toString = ({}).toString.getCall();

// Use the toString function on different things:
alert(toString(3.14159265));  // [object Number]
alert(toString(/regular_expression/g)); // [object RegExp]
alert(toString("a string")); // [object String]
alert(toString(toString)); // [object Function]

// Reference the Array's prototypal function.
var slice = [].slice.getCall();

// Use the slice function on different things:
alert(slice([0,1,2,3], 2));  // 2,3
alert(slice("abcd", 1));  // b,c,d
alert(slice((function(){return arguments})(9,8,7), 0));  // 9,8,7

You may be wondering why we don’t just reference the call() function. Believe it or not, the following code doesn’t work:

var slice = Array.prototype.slice.call;
alert(slice([1,2,3], 0));  // error occurs

The reason the above code doesn’t work is because the reference to slice is not kept within the call() function. To prove this, you can see try the following test:

var slice = [].slice.call;
var toString = ({}).toString;
alert(slice === toString);  // true

The reason slice and toString reference the same function is because on the first two lines, I am actually saving a reference to Function.prototype.call(). Unfortunately, the reference to the slice and toString functions are lost at the point of assigning the references to variables. For this reason, we need to define a new function which will allow you to get a function equivalent to the call() function without losing the reference to the original function. That is why I have the following definition for the getCall() function:

Function.prototype.getCall = function() {
    var fn = this;
    return function() {
        return fn.call.apply(fn, arguments);
    };
};

Now, we can reference a function equivalent to the call() function of another function. One of the biggest advantages of using this approach comes when you have to minify your JS code.

Also, if you would like an equivalent getApply() function, you could use the following definition:

Function.prototype.getApply = function() {
    var fn = this;
    return function(context, args) {
        return fn.apply(context, args);
    };
};

JavaScript – Add Commas To Numbers

At times, I have had to add commas to numbers in order to make them look better in different applications. Even though there isn’t a native way to do this in JavaScript, the code can be quite short, sweet and to the point:

function addCommas(intNum) {
  return (intNum + '').replace(/(\d)(?=(\d{3})+$)/g, '$1,');
}

The downside of the above function is that it will only work for integers. Here is a function that will get the job done for one number or a string which contains one or more numbers:

function delimitNumbers(str) {
  return (str + "").replace(/\b(\d+)((\.\d+)*)\b/g, function(a, b, c) {
    return (b.charAt(0) > 0 && !(c || ".").lastIndexOf(".") ? b.replace(/(\d)(?=(\d{3})+$)/g, "$1,") : b) + c;
  });
}

First this function forces the parameter that was passed in to become a string. Next, a global replace of a regular expression looking for a four-digit or longer number goes through and inserts the commas in the correct place. After that, the result is returned as a string.

Here are some tests that I ran on the function to make sure that it works correctly:

// Delimit a random number.
alert("Random number:  " + delimitNumbers(Math.random() * (1 << 30)));

// Delimit all powers of 2 (from 2^0 to 2^30) in a string.
var powersOf2 = Array.range(31).map(function(i){return 1 << i});
alert("Powers of 2:\n" + delimitNumbers(powersOf2.join("\n")));

One thing you want to keep in mind if you choose to test the delimitNumbers() function with the above code is the fact that you will need to make sure that Array.range() and Array.prototype.map() are correctly defined. I did my test in the ScriptBox which always uses the newest version of jPaq (currently an alpha of v2.0).

PostgreSQL – String To Rows

Working Solution – Custom Function

I have to say that using PostgreSQL has been great compared to MySQL. Recently, though, I ran into an issue while working with iReports designer. I needed to be able to accept a string of comma-delimited integers and then JOIN on those ID’s. Therefore, I started looking for a good string splitting function. At first I was unable to find a native one so I altered this plpgsql function made by pilcrow and added some documentation:

CREATE OR REPLACE FUNCTION split_to_rows(
	IN in_text TEXT,
	IN in_delimiter VARCHAR(20)
)
RETURNS SETOF TEXT AS $$
---------------------------------------------------------------------------
-- Function Name: split_to_rows
-- In-coming Params:
--   in_text [TEXT]
--   in_delimiter [VARCHAR(20)]
-- Out going Param:
--   TEXT
-- Description:
--   Splits the specified text with the specified delimiter and returns a
--   set of rows.
-- Created On: 2011-05-24
-- Author: pilcrow (http://stackoverflow.com/questions/1986491#1987113)
-- Modified By: Chris West
---------------------------------------------------------------------------
  DECLARE
    elems text[];      
  BEGIN
    elems := string_to_array(in_text, in_delimiter);
    FOR i IN array_lower(elems, 1) .. array_upper(elems, 1) LOOP
      RETURN NEXT elems[i];
    END LOOP;
    RETURN;
  END
$$ LANGUAGE 'plpgsql';

The following is an example of using this new function to convert a string of numbers into rows of numbers as integers.

SELECT CAST(split_to_rows('1,2,3,4,5,6', ',') AS INTEGER) AS id;

The Better Solution – Native PostgreSQL Function

After looking into other native solutions, I finally found the regexp_split_to_table function. This is basically called in the same way as pilcrow’s, but with one major difference: you can use regular expressions to split the string into rows. Here is an example of using this new function in the same was as I did the split_to_rows function:

SELECT CAST(regexp_split_to_table('1,2,3,4,5,6', ',') AS INTEGER) AS id;

Escape & Unescape – Deprecated?

Two of the most widely used JavaScript functions that are now deprecated are the escape() and unescape() functions. This means that in order to ensure that your code will continue to work in all future browsers, you should use one of the alternative functions as was indicated on MDN:

  • encodeURI()
  • decodeURI()
  • encodeURIComponent()
  • decodeURIComponent()

What To Do When They Are No More

Since these functions may not always exist, I decided to write the necessary JavaScript code to make sure they can continue to be used:

(function() {
var objGlobal = this;
if(!(objGlobal.escape && objGlobal.unescape)) {
  var escapeHash = {
    _ : function(input) {
      var ret = escapeHash[input];
      if(!ret) {
        if(input.length - 1) {
          ret = String.fromCharCode(input.substring(input.length - 3 ? 2 : 1));
        }
        else {
          var code = input.charCodeAt(0);
          ret = code < 256
            ? "%" + (0 + code.toString(16)).slice(-2).toUpperCase()
            : "%u" + ("000" + code.toString(16)).slice(-4).toUpperCase();
        }
        escapeHash[ret] = input;
        escapeHash[input] = ret;
      }
      return ret;
    }
  };
  objGlobal.escape = objGlobal.escape || function(str) {
    return str.replace(/[^\w @\*\-\+\.\/]/g, function(aChar) {
      return escapeHash._(aChar);
    });
  };
  objGlobal.unescape = objGlobal.unescape || function(str) {
    return str.replace(/%(u[\da-f]{4}|[\da-f]{2})/gi, function(seq) {
      return escapeHash._(seq);
    });
  };
}
})();

Reference

I created these functions based on information found at DevGuru.com.

Forcing A Constructor In JavaScript

Did you know that you can force a function to only act as a constructor? The following is an example of a Person pseudo-class which can be defined with or without the new keyword:

// Defines a person object.
function Person(firstName, lastName, age) { 
  // If called without parameters.
  if(!arguments.length) {
    // If this is a recursive call, allow the properties to now be defined.
    if(arguments.callee.caller === arguments.callee) {
      return this;
    }
    // If this is a non-recursive call, throw an error since the constructor
    // can't be called without parameters.
    else {
      throw new Error("No parameters were specified for the Person object.");
    }
  }
  
  // Allows make sure this function acts as a constructor.
  var me = !(this instanceof arguments.callee) ? new Person : this;
    
  // Define the properties.
  me.firstName = firstName;
  me.lastName = lastName;
  me.age = age;
  
  // Return a reference to the new Person instance.
  return me;
}

// Define the prototypal functions.
Person.prototype = {
  toString : function() {
    return this.firstName + " " + this.lastName + " is " + this.age
      + " years old.";
  }
};

One of the things that you may have noticed is the fact that I am throwing an error if the constructor is called without any arguments. If you don’t want that to happen, you can simply remove that else statement. Everything is probably pretty self explanatory.

The following are two examples which prove the above code actually works:

// Create an instance of a person without the "new" keyword.
var p = Person("Chris", "West", 23);
alert(p.firstName);  // display "Chris"
alert(p instanceof Person);  // display true
alert(p);  // use toString() function

// Create an instance of a person with the "new" keyword.
var p = new Person("Tamara", "Thomas", 21);
alert(p.age);  // display 21
alert(p instanceof Person);  // display true
alert(p);  // use toString() function.

Function Overloading in JavaScript

Method overloading is one of the nice things that exists in real programming languages such as Java. Even though JavaScript starts with “Java”, there are very few similarities between the two languages. Still, due to the power of the scripting language, there is a way to overload functions. The most commonly used method is to simply write some if statements to examine the arguments. Still, I thought it would be nice to be able to overload functions in a more natural way. Therefore, I wrote the following prototype function for functions which will be included in the next version of jPaq:

// Function.prototype.overload - By Chris West - MIT Licensed
Function.prototype.overload = function(fnToAdd, objFilters) {
  var fnOriginal = this;
  return function() {
    var fnToUse = fnToAdd, args = arguments, len = args.length;
    if(objFilters) {
      for(var key in objFilters) {
        if((key == "all" && !objFilters[key].call(this, args))
           || (key == "length" && len != objFilters[key])
           || (/^\d+$/.test(key) && !objFilters[key](args[key]))) {
          fnToUse = fnOriginal;
          break;
        }
      }
    }
    else if(fnToAdd.length !== len) {
      fnToUse = fnOriginal;
    }
    return fnToUse.apply(this, args);
  };
};

First Parameter (fnToAdd)

The first parameter that you pass in must be the function that you want to overload the current function.

Second Parameter (objFilters)

The second parameter is optional. If it is not specified, the only way that fnToAdd will be used is if the amount of arguments specified in the header of that function matches the number of arguments passed in. If the second parameter is specified, it must be an object literal which will be used to determine whether or not to use this function instead of the original. To filter based on a specific parameter, you should make the key be the index of the parameter and the value should be the function that will check that parameter. This filter function will only receive the specified parameter as its only argument. If you want to filter by the amount of parameters passed, you can define the length of the object literal.  If you want use an all-purpose filter function, you can define the all property of the object literal as a function which will receive all of the parameters just as the function would.  In addition, this all-purpose filter function will also receive the this object of the function.  Just as in the case of the other filter functions, if the return value evaluates to false, the original function will be used, otherwise the new function will be used.

Test Code

Now, instead of trying to clarify the above description with more words, let’s let the code do the talking. Assuming that the definition for Function.prototype.overload() appears before this code, the following will test and prove that function overloading can be quite easy:

// Returns a boolean indicating whether or not the argument is an array.
function isArray(arg) {
  return Object.prototype.toString.call(arg) == "[object Array]";
}

// Returns a boolean indicating whether or not the argument is a number.
function isNumber(arg) {
  return Object.prototype.toString.call(arg) == "[object Number]";
}

// The default callAny() function.
function callAny() {
  alert("Default callAny() function was called.");
};

// The callAny() function that will be used if the first parameter is an array.
function callArray(arr) {
  alert("callArray() called with [" + arr.join(", ") + "]");
}

// The callAny() function that will be used if two numbers are passed.
function callNum(num1, num2) {
  alert("callNum() called with " + num1 + " and " + num2);
}

// The callAny function that will be used if no arguments are passed.
function callNone() {
  alert("callNone() called without arguments as expected.");
}

// Easily overload the callAny() function.
callAny = callAny
  .overload(callNone)
  .overload(callArray, {0 : isArray})
  .overload(callNum, {0 : isNumber, length : 2});

/********** Example calls the callAny() **********/
// Calls the default function.
callAny();

// Calls the callNum() function.
callAny(1, 2);

// Calls the default function.
callAny(3);

// Calls the callArray() function.
callAny(["Hello", "World!!!"]);

The first thing to note is that the isNumber() and isArray() functions are defined to filter the arguments. Both callNone(), callArray() and callNum() will overload callAny(). If callAny() is called without any parameters, it acts as if callNone() was invoked. If callAny() is called with the first parameter being an array, it acts as if callArray() was called. If callAny() is called with the first parameter being a number and is called with exactly two parameters, it acts as if callNum() was called. In all other cases the default version of callAny() is called.

Future

I personally think that this may become useful for other JavaScript programmers. Therefore, I plan on incorporating this function into jPaq. Unfortunately, I don’t have an exact date for the next release, therefore, I am fine with you using this code as long as you give me credit for my code. 8)

Private Variables In JavaScript

Often times, many people have made claims that it is not possible to make variables private in JavaScript. I am here to tell you that those people are wrong. There are many implementations from JavaScript guru’s such as Douglas Crockford explaining how to do this. Although these implementations will get the job done, I have noticed that these implementations do not use prototypal functions. On the contrary, the following shows how to give prototypal functions access to private members:

// Immediately executed closure to define a person.
var Person = (function() {
  // The parameter required to retrieve the private data of a person object.
  var theKey = {};
  
  function Person(firstName, lastName, isMale, birthDate) {
    // If birth date is a string, convert it to a date.
    if(typeof birthDate == "string")
      birthDate = new Date(birthDate);
    if(isNaN(birthDate.getTime()) || !(birthDate instanceof Date))
       throw new Error("the passed birth date was invalid");
    // Object literal to keep track of the private data.
    var privateData = {
      firstName : firstName + "",
      lastName : lastName + "",
      isMale : !!isMale,
      birthDate : birthDate
    };
    // If theKey is passed as aKey, the private members of the object are
    // returned.  Since aKey must be theKey in order to retrieve privateData and
    // theKey is an empty object literal, you can be sure that private members
    // will not be returned from the function to any code outside of the
    // closure.  The only non-prototypal function.
    this._ = function(aKey) {
      if(aKey == theKey)
        return privateData;
    };
  }
  
  // Alias for the prototype of the Person object.
  var p = Person.prototype;
  
  // Get or set the first name for the person.
  p.firstName = function(newName) {
    // Get the private data members.
    var pData = this._(theKey);
    // If a parameter was passed, assign the new first name.
    if(!arguments.length)
      return pData.firstName;
    // Set the first name.
    pData.firstName = newName;
    // Allow chainable calls.
    return this;
  };
  
  // Get or set the last name for the person.
  p.lastName = function(newName) {
    // Get the private data members.
    var pData = this._(theKey);
    // If a parameter was passed, assign the new last name.
    if(!arguments.length)
      return pData.lastName;
    // Set the last name.
    pData.lastName = newName;
    // Allow chainable calls.
    return this;
  };
  
  // Gets how many years old the person is.
  p.yearsOld = function() {
    var now = new Date;  // current date
    var birth = this._(theKey).birthDate;  // birth date
    var years = now.getFullYear() - birth.getFullYear();  // difference in years
    now = now.getMonth() * 100 + now.getDate();  // now as MMDD as number
    birth = birth.getMonth() * 100 + birth.getDate();  // now as MMDD as number
    return years - (now < birth);  // Return real years old.
  };
  
  // Gets the birth date.  Makes valueOf an alias so that people can be compared
  // by age.
  p.birthDate = p.valueOf = function() {
    return this._(theKey).birthDate;
  };
  
  // Gets the full name.
  p.fullName = function() {
    var pData = this._(theKey);
    return pData.firstName + " " + pData.lastName;
  };
  
  // Get the string representation of this person.
  p.toString = function() {
    var pData = this._(theKey);
    return "I am a " + this.yearsOld() + " year old "
      + (pData.isMale ? "male" : "female") + " named " + pData.firstName + " "
      + pData.lastName + ".";
  };
  
  // Allow the person pseudo-class to exist outside of this closure.
  return Person;
})();

The code above defines a person pseudo-class in JavaScript. There are four members that are private to each instantiated person object: firstName, lastName, isMale, and birthDate. The first name and last name can be retrieved and set by using the public getters/setters firstName() and lastName(). In addition, fullName() is another accessor method. The person’s birth date can only be retrieved by using either birthDate() or valueOf(). In addition, you can find out how many years old the person is by using yearsOld(). Finally, you can print the person object out as a string to find all of the person’s information.

Now it is time for the tests:

var me = new Person("Chris", "West", true, "October 11, 1492");
var jade = new Person("Jade", "Williams", false, "April 28, 1984");
var harry = new Person("Harry", "Finkelstien", true, "June 4, 1987");

// Show my full name.
alert(me.fullName());

// Change Jade's last name and then show it.
alert(jade.lastName("Flintstone").fullName());

// Show how old harry is.
alert(harry.yearsOld());

// Show everything about the three people.
alert(me);
alert(jade);
alert(harry);

// An attempt to retrieve the private members from the outside.
alert("Could " + (me._({}) == undefined ? "not " : "")
  + "access the private members from the outside.");

I think the comments explain most of the test code pretty well. One thing to note is that, just because you pass in an empty object literal doesn’t mean that it is the same one that is needed to retrieve the private members.

In conclusion, as is demonstrated in my definition of the Person pseudo-class, prototypal functions can retrieve private members.