Ingo Bürk
Ingo Bürk

Reputation: 20033

Adding methods to Object / Number / String prototype

Disclaimer

Scenario

As a developer, I want to add a method someMethod to all Javascript objects, wherein the implementation is different for Object, Number and String.

I want the solution to meet the following acceptance criteria:

[1] Minfication removes strict directives
[2] Any way to force strict mode in node?

Upvotes: 5

Views: 784

Answers (2)

Ingo Bürk
Ingo Bürk

Reputation: 20033

My own solution

While trying to figure this out, I have encountered a few problems causing one or another acceptance criterium to break (e.g. a problem described in [1]). After some time I came up with the following solution which seems to work for me. This can be written in a more generic way, of course.

(function () {
    'use strict';

    var methodName = 'someMethod',
        /** Sample method implementations */
        __someMethod = {
            'object': function () {
                var _this = this.valueOf();

                return ['Object'].concat( Array.prototype.slice.call( arguments ) );
            },

            'number': function () {
                var _this = this.valueOf();

                return ['Number'].concat( Array.prototype.slice.call( arguments ) );
            },

            'string': function () {
                var _this = this.valueOf();

                return ['String'].concat( Array.prototype.slice.call( arguments ) );
            },

            'boolean': function () {
                var _this = this.valueOf();

                return ['Boolean', _this];
            }
        };

    if( Object.defineProperty ) {
        Object.defineProperty( Number.prototype, methodName, {
            value: __someMethod['number'],
            writable: true
        } );

        Object.defineProperty( String.prototype, methodName, {
            value: __someMethod['string'],
            writable: true
        } );

        Object.defineProperty( Boolean.prototype, methodName, {
            value: __someMethod['boolean'],
            writable: true
        } );

        Object.defineProperty( Object.prototype, methodName, {
            value: __someMethod['object'],
            writable: true
        } );
    } else {
        Number.prototype[methodName] = __someMethod['number'];
        String.prototype[methodName] = __someMethod['string'];
        Boolean.prototype[methodName] = __someMethod['boolean'];
        Object.prototype[methodName] = __someMethod['object'];
    }
})(); 

Edit: I updated the solution to add the solution for the problem mentioned in [1]. Namely it's the line (e.g.) var _this = this.valueOf();. The reason for this becomes clear if using

'number': function (other) {
    return this === other;
}

In this case, you will get

var someNumber = 42;
console.log( someNumber.someMethod( 42 ) ); // false

This, of course, isn't what we'd want (again, the reason is stated in [1]). So you should use _this instead of this:

'number': function (other) {
    var _this = this.valueOf();
    return _this === other;
}

// ...

var someNumber = 42;
console.log( someNumber.someMethod( 42 ) ); // true

[1] Why does `typeof this` return "object"?

Upvotes: 3

Paul
Paul

Reputation: 141839

Creating a wrapper object (note this is just an example, it is not very robust):

var $ = (function(){
  function $(obj){
    if(!(this instanceof $))
        return new $(obj);

    this.method = function(method){
        var objtype = typeof obj;
        var methodName = method + objtype[0].toUpperCase() + objtype.substr(1);
        typeof _$[methodName] == 'function' && _$[methodName].call(obj);
    }
  }

  var _$ = {};

  _$.formatNumber = function(){
    console.log('Formatting number: ' + this);
  }

  _$.formatString = function(){
    console.log('Formatting str: "' + this + '"');
  }

  _$.formatObject = function(){
    console.log('Formatting object: ');
    console.log(JSON.stringify(this));
  }

  return $;
})();

Usage:

var num = 5;
var str = 'test';
var obj = {num: num, str: str};

var $num = $(num);
$num.method('format');

$(str).method('format');
$(obj).method('format');

Demo

Upvotes: 1

Related Questions