Yes, this is 100% possible with JavaScript!
You can Skip to the end for the solution directly or read this for a detailed explanation.
The Approach
The solution depends on how you want to implement it as the runtime environment comes into play. Browsers implement runtime environments that enforce ECMAScript standards they adopt while Node.js is a fork on V8 and has it's own modules that deals with how standard
Below, I will take a use case and give two solutions and direct solution to the example problem of your question:
- An Universal Solution that you can implement and it will work on the browser AND on Node.js
- Node.js specific solution.
- Solution to the exact Use Case of OP.
Note: This will also help those studying Data Structures and trying to do a JavaScript implementation.
The Problem
Let's take a Use Case similar to the OP's use case to understand this better. Suppose you are building the Array Data Structure from scratch as a custom xArray
constructor. For simplicity let's only implement the push
method so we can push some data and then try to output the result exactly the way the JavaScript Array constructor creates objects and the prints the array when we console.log
the object or return it from a function.
We will also need the static method XArray.isArray(input)
so we can test if the instance of the object is the same as the constructor.
If we simply console.log
the Object without adding the solution, we will get something that looks like:
Undesired Solution:
const xArray = new XArray();
xArray.push('a', 'b', 'c', 'd', 'e');
console.log(xArray);
// Prints: XArray { '0': 'a', '1': 'b', '2': 'c', '3': 'd', '4': 'e' }
But that's not what we want. We need the Object.values(xArray)
just like in the OP's use case, user.name
is required as the output and not the whole User { name: 'example', password: 'password' }
So, instead, this is the output we want:
Desired Solution:
// Test function that takes an array and returns it.
const returnArr = array => array;
/************************************************************************************************/
/** Array using custom XArray constructor **/
/************************************************************************************************/
const xArray = new XArray();
xArray.push('a', 'b', 'c', 'd', 'e');
console.log(xArray); // Prints: [ 'a', 'b', 'c', 'd', 'e' ]
console.log(returnArr(xArray)); // Returns: [ 'a', 'b', 'c', 'd', 'e' ]
console.log(XArray.isArray(xArray)); // Returns: true
Let's build the solution for the array and then simply implement that for the OP's question.
The Solution
Solution 1 - Universal Solution
for all Runtimes
We will modify the console.log()
inside the constructor function by modifying global object that has the log
method.
P.S. - You can console.log(console)
to see all the console methods.
class XArray {
constructor() {
Object.defineProperties(this, {
length: {
writable: true,
enumerable: false,
configurable: false,
value: 0,
},
});
const runtimeConsole = console;
console = {
...console,
log: function (data) {
if (XArray.isArray(data)) runtimeConsole.log(Object.values(data));
else runtimeConsole.log(data);
},
};
}
push(...elements) {
for (const element of elements) {
this[this.length] = element;
this.length++;
}
}
static isArray(array) {
return array instanceof XArray;
}
}
Solution 2: For Node.js
using util
module
We will be using the util.inspect.custom
Symbol from the util
module in node.js
.
import util from 'util';
class XArray {
constructor() {
Object.defineProperties(this, {
length: {
writable: true,
enumerable: false,
configurable: false,
value: 0,
},
});
}
push(...elements) {
for (const element of elements) {
this[this.length] = element;
this.length++;
}
}
[util.inspect.custom]() {
return Object.values(this);
}
}
Solution 3: Solving the OP's Use Case
So you can use either Solution 1 or Solution 2 to solve your Use Case:
Solution 3A: Universal Solution
Using Solution 1
class User {
constructor(name, password) {
this.name = name;
this.password = password;
const runtimeConsole = console;
console = {
...console,
log: function (data) {
if (User.isUser(data)) runtimeConsole.log(data.name);
else runtimeConsole.log(data);
},
};
}
static isUser(user) {
return user instanceof User;
}
}
Solution 3B: For Node.js
Using Solution 2
import util from 'util';
function User(name, password) {
this.name = name;
this.password = password;
[util.inspect.custom]() {
return this.name;
}
}
Testing Solution 3A and 3B:
// Test function that takes an user and returns it
const user = new User('example', 'password');
// Function that takes an user and returns it
const returnUser = user => user;
console.log(user); // Prints: example
console.log(returnUser(user)); // Prints: example
Sidenote:
import
is an ES6 convention that will not work in Node.js by default unless you have the package.json
file have a "type": "module"
setting enabled. This is because Node by default honours the CommonJS convention.
If this is confusing, replace the import line and use:
const util = require('util');