I'll answer the bountied sub-question:
I would like to know how to have the new property displayed on the terminal when doing console.log(url) here. I've tried with defineProperty(), writable: true, enumerable: true, etc. to no avail. Should show the properties in Node.js.
After research, I came across this question. Thanks to this method, you can edit the output on node:
let { URL } = require('url');
class MyURL extends URL {
    constructor(url, base) {
        super(url, base);
        this.base = base;
    }
    [require('util').inspect.custom](){
        return `MyURL {base: ${this.base}}`;
    }
}
let u = new MyURL('abc.html','http://www.example.com/about')
console.log(u);
This gives, as you can imagine, this output: MyURL {base: http://www.example.com/about}. However, if I assume well, that's only half the work done, as we don't have all the other properties printed. I am however unable to have a perfect result.
If you don't care about the performances and just want the flat properties, you can use Object.assign to make a copy of your object without the class:
let { URL } = require('url');
class MyURL extends URL {
    constructor(url, base) {
        super(url, base);
        this.base = base;
    }
    [require('util').inspect.custom](){
        let res = require('util').inspect(Object.assign({}, this));
        return `MyURL ${res}`;
    }
}
let ur = new MyURL('abc.html','http://www.example.com/about')
console.log(ur);
this gives the following:
MyURL {
  base: 'http://www.example.com/about',
  [Symbol(context)]: URLContext {
    flags: 400,
    scheme: 'http:',
    username: '',
    password: '',
    host: 'www.example.com',
    port: null,
    path: [ 'abc.html' ],
    query: null,
    fragment: null
  },
  [Symbol(query)]: URLSearchParams {}
}
You can achieve the same without copying using some dirty trick (I'm not sure if it's a good idea to do this though):
let { URL } = require('url');
class MyURL extends URL {
    constructor(url, base) {
        super(url, base);
        this.base = base;
    }
    [require('util').inspect.custom](){
        this.__proto__ = Object.prototype;
        let res = require('util').inspect(this);
        this.__proto__ = MyURL.prototype;
        return `MyURL ${res}`;
    }
}
let ur = new MyURL('abc.html','http://www.example.com/about')
console.log(ur);
But I must admit, it is a bit obscure to me. In case this is not a good solution for you, another possibility is to use a URL instance for the inspect call:
let { URL } = require('url');
class MyURL extends URL {
    constructor(url, base) {
        super(url, base);
        this.base = base;
    }
    [require('util').inspect.custom](){
        return `MyURL { base: ${this.base}, super: ${require('util').inspect(new URL(this))} }`;
    }
}
let u = new MyURL('abc.html','http://www.example.com/about')
console.log(u);
or the faster and dirtier way:
let { URL } = require('url');
class MyURL extends URL {
    constructor(url, base) {
        super(url, base);
        this.base = base;
    }
    [require('util').inspect.custom](){
        this.__proto__ = URL.prototype;
        let res = require('util').inspect(this);
        this.__proto__ = MyURL.prototype;
        return `MyURL { base: ${this.base}, super: ${res} }`;
    }
}
let ur = new MyURL('abc.html','http://www.example.com/about')
console.log(ur);
Giving the output:
MyURL { base: http://www.example.com/about, super: URL {
  href: 'http://www.example.com/abc.html',
  origin: 'http://www.example.com',
  protocol: 'http:',
  username: '',
  password: '',
  host: 'www.example.com',
  hostname: 'www.example.com',
  port: '',
  pathname: '/abc.html',
  search: '',
  searchParams: URLSearchParams {},
  hash: ''
} }
This can be perfected with some string editing.
The last solution I have is to re-create the whole print, by iterating through all the getters of URL and printing them / adding them to an object to finally print:
let { URL } = require('url');
class MyURL extends URL {
    constructor(url, base) {
        super(url, base);
        this.base = base;
    }
    [require('util').inspect.custom](){
        let res = {};
        for (var key in this) {
            res[key] = this[key];
        }
        return `MyURL ${require('util').inspect(res)}`;
    }
}
let u = new MyURL('abc.html','http://www.example.com/about')
console.log(u);
this gives:
MyURL {
  base: 'http://www.example.com/about',
  toString: [Function: toString],
  href: 'http://www.example.com/abc.html',
  origin: 'http://www.example.com',
  protocol: 'http:',
  username: '',
  password: '',
  host: 'www.example.com',
  hostname: 'www.example.com',
  port: '',
  pathname: '/abc.html',
  search: '',
  searchParams: URLSearchParams {},
  hash: '',
  toJSON: [Function: toJSON]
}
If you don't care about the MyURL  prefix and prefer to have the coloration, you can simply return res instead of a string.