Reputation: 37
I am trying to find a way to call a custom method on a string primitive without modifying the native String
object.
String.prototype.addOne = function() { return this.length + 1};
let str = new String('abc')
str.addOne() // 4
The problem with the above code is that new strings will also have the new method, and the above method creation may override other primitive modifications made inside libraries, or other areas of the code base, for example:
String.prototype.addTwo = function() {return this.addOne + 1}
str.addTwo() // 5
String.prototype.addOne = function() { return this.length + 10};
str.addOne() // 13
str.addTwo() // 14, oops
Are there any solutions that allow me to create a clone of a String
Object where i can safely modify its prototype without having to mutate the native global String
object?
EDIT:
I am specifically asking if there is a way to do this allows me to add methods to a Primitive String some have suggested extending the String class, adding a method and then returning a String
Object. However, this is not the same as a primitive string Object. I would basically like to be able to call custom methods like this :
class CustomString extends String{
someMethod(){
return 'someValue'
}
}
let str = '123'
str.someMethod() // '123' <<< this
let str2 = new CustomString('123')
str2.someMethod() // CustomString { [Iterator] 0: '4', 1:'5'. 2: '6'} <<< not this
This works, but then the original problem persists, in that we have mutated the global String
object
String.prototype.someMethod = function() {return 'someValue'}
let str3 = '123'
str3.someMethod() // someValue
Upvotes: 0
Views: 483
Reputation: 18619
Just create a subclass:
class CustomString extends String{
addOne(){...}
}
And then simply:
new CustomString("asd").addOne()
This class will be very similar to String
, but you can create additional properties without conflicting with the primitive strings and the native String
class.
Even instanceof
will work with it as well:
new CustomString() instanceof String //true
But note that you won't be able to create primitive strings with this constructor:
String(1) //"1"
CustomString(1) //Error
EDIT: According to the edit to the question:
After a lot of messing around, I've found the way to patch properties to primitives' prototypes without affecting their constructors:
function CustomString(from){
let string
if(new.target){ //Whether or not was called as constructor
string = new String(from)
}else{
string = String(from)
}
Object.assign(Object.getPrototypeOf(string),CustomString.prototype)
return string
}
//Add your custom properties like this:
CustomString.prototype.addOne=function(){return this.length+1}
//Without new, creates a primitive string
const primitiveCustomString = CustomString('asd')
//With new, creates a string object
const objectCustomString = new CustomString('asd')
console.log(primitiveCustomString) //"asd"
console.log(objectCustomString) //String{0:"a",1:"s",2:"d",addOne(){...}}
console.log(primitiveCustomString.addOne()) //4
console.log(objectCustomString.addOne()) //4
//You can even concatenate it together with normal strings, the custom properties still remain
console.log(("asd" + primitiveCustomString + "asd").addOne()) //10
console.log(("asd" + objectCustomString + "asd").addOne()) //10
Upvotes: 0
Reputation: 5072
You can write a factory-function.
function addoneable_string(s) {
let ns = new String(s);
ns.addOne = function() { return this.length + 1};
return ns;
}
let s = addoneable_string("1");
console.log( s.addOne() );
Upvotes: 0
Reputation: 370819
Sounds like you might want to make a class that extends String
:
(() => {
// In one module:
class SpecialString extends String {
addOne() {
return this.length + 1
}
}
const str = new SpecialString('abc');
console.log(str.addOne()) // 4
})();
(() => {
// In another module:
class SpecialString2 extends String {
addTwo() {
return this.addOne() + 1
}
addOne() {
return this.length + 10
}
}
const str = new SpecialString2('abc');
console.log(str.addTwo());
console.log(str.addOne());
console.log(str.addTwo());
})();
Upvotes: 1