Extend the primitive in the current region only

Is it possible to copy a primitive like String

so that it can only be extended in the current function?

var foo = function() {
    var String = // somehow clone String (the primitive function)
    String.prototype.first = function() { return this.charAt(0) };
    return 'abc'.first();
}
foo(); // returns 'a'
'abc'.first(); // returns TypeError "abc".first is not a function

      

The solution is to either copy the primitive, which is not possible, or destroy the new method after the function ends ...

+3


source to share


3 answers


String

is global, and if you change it or add it to its prototype, the changes are by definition global. To revert changes, you must revert them.

You can usually try to get a custom subclass and add a new prototype method to it, but built-in types like String are notoriously difficult to subclass, and even if you could call it something like MyString('abc').first()

.

Your problems stem from your misconception about prototype addition String

. Dirty prototypes are never recommended. I understand your idea of ​​this, somehow quickly removing it after adding and using it, but this is unrealistic and the approach setTimeout

is a terrible, unreliable hack.

However, if you really insist on adding to the prototype String

, then one idea is to add all of your new instance methods to a single property that is less likely to collide with things. Let's call him Utils

. We would like to be able to call



'abc'.Utils.first()

      

But how can we make this work? We define a getter on a property Utils

that returns a hash of the methods. Using getter (instead of value

) provides us this

which we can pass to methods using bind

.

Object.defineProperty(String.prototype, 'Utils', { 
  get: function() {
    return {
      first: function() { return this.charAt(0); }.bind(this)
    };
  }
});

> 'abc'.Utils.first()
< "a"

      

+3


source


Why do you want to expand String.prototype

? The easiest way is to create a local function:



alert(foo());        // "a"
alert(first("abc")); // ReferenceError: first is not defined

function foo() {
    return first("abc");

    function first(string) {
        return string.charAt(0);
    }
}
      

Run code


There is no advantage when using methods over functions.

+1


source


String.define = function(name, fn) {
    // Don't overwrite existing method
    if(String.prototype[name]) return false;

    // Make new method
    Object.defineProperty(String.prototype, name, {
        value: fn,
        configurable: true,
        enumerable: false,
        writable: false
    });

    // Delete method once parent function returns
    setTimeout(function() { 
        delete String.prototype[name] 
    }, 0);
}

var foo = function() {
    String.define('first', function() { 
        return this.charAt(0); 
    });
    return 'abc'.first();
}

foo(); // returns 'a'
'abc'.first(); // returns TypeError

      

This works by creating a method on the String (global) and only deleting it when the containing function is finished. It is effective to make it exist only in this area. I don't know if the asynchronous code executed while foo () is being processed will have access to String.prototype.first, but it would be interesting to check ...

edit: Looked closely and it doesn't work. setTimeout, which erases the prototype method, is only fired after the outermost parent function returns. In this snippet, the second call to ".first" runs outside of the function on it.

var foo = function() {
    console.log((function () {
        String.define('first', function() {
            return this.charAt(0);
        });
        return 'abc'.first();
    })());
    console.log('abc'.first())
}

      

0


source







All Articles