I know I can create a toString()
function on an object, so that every time it's printed or treated like a string it will first stringify the object with that function.
Is it possible to do that directly so I can use String object functions on the object?
var SomeObject = function(a, b){
this.a = a;
this.b = b
}
SomeObject.prototype.toString = function(){
return [ this.a, this.b ].join(' ')
}
var objInstance = new SomeObject('this', 'that');
console.log(objInstance + '') // This that
console.log(("" + objInstance).split('')) // [ 't', 'h', 'i', 's', ' ', 't', 'h', 'a', 't' ]
console.log(objInstance.split()) // Error
Is it possible to do so that the object "behaves" like a string when a String function is called on it?
In other words, I'd like objInstance.split()
to have the same result as ("" + objInstance).split('')
, and also objInstance.length
or objInstance.match(/something/)
, etc.
The JSON.stringify() method converts a JavaScript value to a JSON string, optionally replacing values if a replacer function is specified or optionally including only the specified properties if a replacer array is specified.
To be clear, the output looks like JSON but in fact is just javascript. JSON. stringify works well in most cases, but "fails" with functions.
parse() The JSON. parse() method parses a JSON string, constructing the JavaScript value or object described by the string.
The JSON. stringify() method in Javascript is used to create a JSON string out of it. While developing an application using JavaScript, many times it is needed to serialize the data to strings for storing the data into a database or for sending the data to an API or web server.
You can let your objects inherit from String
so that all string methods become available:
class SomeObject extends String {
constructor(a, b) {
super(a + " " + b);
this.a = a;
this.b = b;
}
}
var obj = new SomeObject('this', 'that');
console.log(obj.split(""));
No need to use complicated Proxy
solutions :-)
All the String.prototype
methods (except for .toString
, .valueOf
and [Symbol.iterator]
) are "intentionally generic; [they do] not require that its this
value be a String
object. Therefore, [they] can be transferred to other kinds of objects for use as a method." You can call them on any value, they will coerce it to a string (using .toString()
or .valueOf
as usual).
You don't even need to use ES6 class extends
to inherit from the builtin (which also makes your string value immutable), it works in ES5 as well:
function SomeObject(a, b) {
this.a = a;
this.b = b;
}
SomeObject.prototype = Object.create(String.prototype);
SomeObject.prototype.constructor = SomeObject;
SomeObject.prototype.toString = function() {
return this.a + " " + this.b;
};
var obj = new SomeObject('this', 'that');
console.log(obj.split(""));
One option would be to return a Proxy
that checks whether the property exists on String.prototype
, and if it does, calls that property with the string that represents the object:
// Declare the proxy handler up front here
// to avoid unnecessary creation of duplicate handler objects
const handler = {
get(obj, prop) {
if (obj[prop] !== undefined) {
return obj[prop];
}
const stringMethod = String.prototype[prop];
if (stringMethod) {
return stringMethod.bind(obj.a + ' ' + obj.b);
}
},
};
const SomeClass = function(a, b) {
this.a = a;
this.b = b
return new Proxy(this, handler);
}
const instance = new SomeClass('this', 'that');
// String methods:
console.log(instance.trim());
console.log(instance.includes('this'));
console.log(instance.includes('somethingelse'));
console.log(instance.split(''));
// Can still assign and retrieve values directly on the object as normal:
instance.foo = 'foo';
console.log(instance.foo);
One option to extend the SomeObject
too, something like this.
var SomeObject = function(a, b){
this.a = a;
this.b = b
}
SomeObject.prototype.toString = function(){
return [ this.a, this.b ].join(' ')
};
SomeObject.prototype.split = function() {
return String.prototype.split.apply(this.toString(), arguments);
};
var objInstance = new SomeObject('this', 'that');
console.log(objInstance + '') // this that
//console.log(("" + objInstance).split('')) // [ 't', 'h', 'i', 's', ' ', 't', 'h', 'a', 't' ]
console.log(objInstance.split(''));
In a comment you've asked:
I was thinking about doing this programmatically by doing it for all functions - but is there a way to list all functions of an object?
Yes, you'd use getOwnPropertyNames
on String.prototype
and filter out the ones that aren't functions:
var SomeObject = function(a, b){
this.a = a;
this.b = b
}
SomeObject.prototype.toString = function(){
return [ this.a, this.b ].join(' ')
};
Object.getOwnPropertyNames(String.prototype).forEach(function(name) {
var fn = String.prototype[name];
if (name !== "toString" && typeof fn === "function") {
SomeObject.prototype[name] = function() {
return fn.apply(this.toString(), arguments);
};
}
});
var objInstance = new SomeObject('this', 'that');
console.log(objInstance + '') // this that
//console.log(("" + objInstance).split('')) // [ 't', 'h', 'i', 's', ' ', 't', 'h', 'a', 't' ]
console.log(objInstance.split(''));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With