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 ...
source to share
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"
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);
}
}
There is no advantage when using methods over functions.
source to share
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())
}
source to share