Tag Archives: Prototype

JavaScript Snippet – getClass()

If you have been using JavaScript for a little bit you probably already know how to determine a variable’s class constructor, but just in case you are overthinking it here is a hint: variable.constructor. :-) Of course, many times I like to make functions that will spit my results for me so here is one that will take any variable and spit out its class constructor:

OK, yeah I know that JavaScript doesn’t really have classes but prototypes but most people think of them as classes so that is why this is called getClass(). The one thing you will notice is that if null or undefined is passed into the function, the same value will be passed back since those are the only two things in JavaScript that don’t have corresponding prototypes. Have fun! :cool:

JavaScript Snippet – String.prototype.after()

WARNING:
Extending native prototypes is frowned upon by many JS engineers but can be helpful as long as the extensions are properly documented in the codebase.
SCRIPTER’S DISCRETION IS ADVISED. :lol:

Yesterday I added a post about String.prototype.before(...). As is explained within the post, this function can be used to easily extract a substring before a given target. Of course, if you can get what comes before a target you should be able to get what comes after a target too, right? Here is a function that makes that possible:

As indicated in the comments, this function can take a target (string or regular expression) to key off of to extract the desired substring. It also takes an optional second argument used for indicating the occurrence of the target to key off of. For instance, if you wanted to get the string that comes after the second comma in "Uno, dos, tres, cuatro, y cinco" you could use the following code:

var str = "Uno, dos, tres, cuatro, y cinco";
var afterFirstTwo = str.after(',', 2);

Here are some other examples that I used to test this function:

As usual, feel free to use this function in your own projects. Have fun! :cool:

JavaScript Snippet – String.prototype.before()

WARNING:
Extending native prototypes is frowned upon by many JS engineers but can be helpful as long as the extensions are properly documented in the codebase.
SCRIPTER’S DISCRETION IS ADVISED. :lol:

Even though its NOT encouraged to extend native prototypes, at times you may find that doing so is pretty useful. One extension that you may find useful is String.prototype.before(...) which can be used to return the substring before a specified target. Here is the definition:

First I think its worth mentioning that depending on your preference you could choose to rename this function as String.prototype.leftOf(...) to clearly identify what it does. This function takes at least a target to find in the string which is either a string or a regexp. You may also optionally pass in a second argument which indicates the occurrence of the target to key off of. For example, if you wanted to extract the substring before the second comma in "one, two, three, and four" you could do something like the following:

var str = "one, two, three, and four";
var firstTwo = str.before(',', 2);

Of course, that is just one simple example of what you can do with this prototype extension. Check out some tests that exemplify how to use this helpful function:

Most likely if you like this function you will also want to check out the String.prototype.after(...) post. Enjoy using this helpful utility function. :cool:

JavaScript – Simplest Inheritance Before ES5

One of the great things about reading through Douglas Crockford’s site is that you get to learn about how certain things like prototypal inheritance was implemented prior to ECMAScript 5. Since then Object.create() made its way into JavaScript and has been available in most modern browsers for a while. If you haven’t read through Crockford’s site or seen how prototypal inheritance was done before, here is a quick overview:

You can click here to test out the code yourself. As you may have noticed, the key to prototypal inheritance is as follows (please ignore the names of these prototypes disguising themselves as classes :smile:):

SubClass.prototype = new Class();

Unfortunately, at times you may not be able to safely execute the constructor of the prototype which is being inherited (which in this case would be Class). In order to get around it, you can create a surrogate function whose prototype will become that of the prototype to be inherited:

function SurrogateClass(){}
SurrogateClass.prototype = Class.prototype;
SubClass.prototype = new SurrogateClass();

Unfortunately, it isn’t the most memorable sequence so let’s turn this into a simple function:

function inherit(Class, SubClass) {
    function SurrogateClass(){}
    SurrogateClass.prototype = Class.prototype;
    SubClass.prototype = new SurrogateClass();
}

Finally, let’s minify it:

function inherit(C,S,p){function O(){}O[p='prototype']=C[p];S[p]=new O}

OK, so this is minification to an extreme since I placed p in the function’s signature. I also went a bit far by sketchily defining p in the left-hand side of the assignment of the prototype to the surrogate function. Even though the above code seems to work, just to be safe, here is a slightly longer, more trustworthy definition:

In the end, both of these definitions are extremely small so I’d say even prior to ES5, prototypal inheritance wasn’t as difficult as one might have thought. :cool:

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 (v1.1) - 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, getters:Array<=string>, prototype:Object, 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(fakeClass) {
  var hasOwnProperty = {}.hasOwnProperty;
 
  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]
        : {};
      if (superClass) {
        this.superClass = superClass;
      }
      try {
        return constructor.apply(this, arguments);
      }
      finally {
        if (superClass) {
          delete this.superClass;
        }
      }
    };
 
    // 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(){});

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 – String.prototype.toProperCase()

Now Available in YourJS

At times you may need to format a string so that it is more appealing. One function that does this is String#toProperCase() because it actually capitalizes the first character of each word. Even though I already had a simple version of this defined in jPaq v1 I thought it would be nice to add the option to lower-case the remaining characters. Here is the updated version of the function definition:

String.prototype.toProperCase = function(opt_lowerCaseTheRest) {
  return (opt_lowerCaseTheRest ? this.toLowerCase() : this)
    .replace(/(^|[\s\xA0])[^\s\xA0]/g, function(s){ return s.toUpperCase(); });
};

Examples of using this function are as follows:

var msg = "Where in the WORLD is Carmen Sandiego?";
alert(msg.toProperCase());  // Where In The WORLD Is Carmen Sandiego?
alert(msg.toProperCase(true));  // Where In The World Is Carmen Sandiego?

At this point this change is scheduled to appear in the next version of jPaq but seeing as how I still don’t know when I will have time to release it I figured it would be a good idea to publicly release it here for everyone to use. Have fun. 8-)

JavaScript Snippet – String.prototype.count

One string method that I found today in Python is the count function to determine how many times a given substring appears in a string. Below is the equivalent of this function in JavaScript:

String.prototype.count = function(target, start, end) {
  start = start || 0;
  end = end == null ? this.length : end;
  return this.slice(start, end).split(target).length - 1;
};

It is important to note that if you pass a regular expression as the target instead of a string, an incorrect count may be returned. If you need this to work with regular expressions, you can use the following instead:

(function(toString) {
  String.prototype.count = function(target, start, end) {
    start = start || 0;
    end = end == null ? this.length : end;
    var me = this.slice(start, end);
    if (toString.call(target) == '[object RegExp]') {
      if (!target.global) {
        target = new RegExp(target.source,
          (target.ignoreCase ? 'i' : '')
          + (target.multiLine ? 'm' : '')
          + 'g');
      }
      var count = 0;
      me.replace(target, function() {
        count++;
      });
      return count;
    }
    return me.slice(start, end).split(target).length - 1;
  };
})({}.toString);

This function takes one required argument and two optional arguments. The required argument is the substring to be counted. The second argument is the starting point of the string to be searched. The third argument is the ending point of the string to be searched. If negative values are given as the starting or ending point, they will be calculated from the end of the string. Happy coding! 8-)

JavaScript – Creating A JS Library with Optional Prototypes

One thing that I started working on last year, but unfortunately never released, was a version of jPaq which provides the ability to pick whether or not prototypal functions are created. The reason I started working on this was to somewhat satisfy the complaints of those who feel that native prototypes should not be modified. You may wonder how a JavaScript library could be written with the option of adding the corresponding prototypal functions. The following is an example of such a library:

// EXAMPLE JAVASCRIPT LIBRARY USING PROTO
(function(slice, undefined) {
    // Function that adds the specified function as a prototypal function to the
    // specified class with the specified name.
    function proto(theClass, fnName, fn) {
        return theClass.prototype[fnName] = function() {
            return fn.apply(undefined, [this].concat(slice.call(arguments, 0)));
        };
    }

    // Array of prototypal functions to add.
    var protosToAdd = [
        [String, 'lstrip', trimLeft],
        [String, 'rstrip', trimRight],
        [String, 'strip', trim]
    ];

    // Trim functions to be added to jPaq.
    function trimLeft(s) {
        return s.replace(/^\s+/, '');
    }
    function trimRight(s) {
        return s.replace(/\s+$/, '');
    }
    function trim(s) {
        return trimLeft(trimRight(s));
    }

    // Defining the library (in this case jPaq) in the global namespace.  The
    // library comes built-in with the trim functions but if the protoAll
    // function is called the trim function will be prototypalized.
    jPaq = {
        proto: proto,
        trimLeft: trimLeft,
        trimRight: trimRight,
        trim: trim,
        protoAll: function() {
            for (var i = protosToAdd.length; i--;) {
                proto.apply(0, protosToAdd[i]);
            }
        }
    };
})([].slice);

If you were to run the above code block, you would end up defining the scaled-down jPaq library object. On the other hand, at the point no prototypes were actually modified. So, how does this code actually help us? The power is in the proto function which is called by the protoAll function. If you are a developer who doesn’t mind a native prototype being updated (String.prototype in this case), you could execute the following:

jPaq.protoAll();

At this point, executing jPaq.protoAll is the equivalent of the following:

jPaq.proto(String, 'lstrip', jPaq.trimLeft);
jPaq.proto(String, 'rstrip', jPaq.trimRight);
jPaq.proto(String, 'strip', jPaq.trim);

Either one of the above code blocks results in definitions for String.prototype.lstrip, String.prototype.rstrip, and String.prototype.strip. These definitions use the corresponding trim functions defined in the first code block but the only difference is that the context object is passed as the first (and in this case only) argument to the corresponding function. As you may have guessed, this can be very useful, assuming that you design your non-prototypal functions to take the first argument that would be passed in as the context object in a prototypal environment.

Even though this proto function is currently something that I have defined for an example version of jPaq, this could be really be used for almost any JavaScript library. Therefore, if you are creating your own JS library and want to distribute it with the option to add prototypal functions, the following is the function snippet that you can add:

var proto = (function(slice, undefined) {
    return function(theClass, fnName, fn) {
        return theClass.prototype[fnName] = function() {
            return fn.apply(undefined, [this].concat(slice.call(arguments, 0)));
        };
    };
})([].slice);

I hope this helps. 8-)

JavaScript – String.prototype.split Fix

In this post I proved that the String.prototype.split function can behave differently in IE8 and below than it does in other browsers. For that reason, I wrote the following code that will fix the issue so that split should work the same in all browsers:

(function(split, toString, slice) {
  String.prototype.split = ','.split(/(()(,)())/, 5).join('|') == '|,||,|'
    ? split
    : function(delim, limit) {
      var me = this;
      if (toString.call(delim).slice(8, -1) == 'String') {
        return split.apply(me, arguments);
      }

      var end, start = 0, ret = [];
      me.replace(
        new RegExp(delim.source,
          'g' + (delim.ignoreCase ? 'i' : '') + (delim.multiline ? 'm' : '')),
        function(delim) {
          var arr = slice.call(arguments, 1, -1);
          end = arr.splice(-1)[0];
          ret.push.apply(ret, [me.slice(start, end)].concat(arr));
          start = end + delim.length;
          return delim;
        }
      );
      ret.push(me.slice(start));
      return limit > 0 ? ret.slice(0, limit) : ret;
    };
})(''.split, {}.toString, [].slice);

It is important to note that there is a way to improve the efficiency of this function if you plan on using it on big strings, but will also be setting the limit every time. On the other hand, most people probably don’t use the limit parameter of the split function so there is no reason to change the code in most cases.

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 ;)).