简体   繁体   English

如何扩展 nodejs 的 url 模块中的 URL 类以添加属性?

[英]How to extend the URL Class in url module of nodejs to add a property into it?

I am trying to extend the URL class and add a property to customize it.我正在尝试扩展 URL 类并添加一个属性来自定义它。 But its not working.但它不起作用。

let { URL } = require('url');

class MyURL extends URL {
    constructor(url, base) {
        super(url, base);
        this.base = base;
    }
}
let ur = new MyURL('abc.html','http://www.example.com/about')
console.log(ur);

it logs它记录

MyURL { 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: '' } MyURL { href: ' http://www.example.com/abc.html ', 来源: ' http://www.example.com ', 协议: 'http:', 用户名: '', 密码: '' ,主机:'www.example.com',主机名:'www.example.com',端口:'',路径名:'/abc.html',搜索:'',searchParams:URLSearchParams {},哈希:'' }

Notice it doesn't have the base property.请注意,它没有 base 属性。 Why is it happening?为什么会这样?

How can I make it have the property base with the base provided in the constructor by extending URL ?如何通过扩展URL使其具有构造函数中提供的基础的属性基础?

Try console.log(ur.base) and you'll see your base class instance attribute.试试console.log(ur.base)你会看到你的base类实例属性。 The reason why you could not see it before is that console.log automatically uses toString() method of URL class.之前看不到的原因是console.log自动使用了URL类的toString()方法。 So you have to override toString in a child class as well and include base attribute.因此,您还必须在子类中覆盖toString并包含base属性。

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.我想知道在执行 console.log(url) 时如何在终端上显示新属性。 I've tried with defineProperty(), writable: true, enumerable: true, etc. to no avail.我尝试过使用defineProperty()、可写:真、可枚举:真等,但无济于事。 Should show the properties in Node.js.应该在 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} .正如您可以想象的那样,这给出了以下输出: 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:如果您不关心性能并且只想要平面属性,则可以使用Object.assign来制作没有类的对象的副本:

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:如果这对您来说不是一个好的解决方案,另一种可能性是使用URL实例进行inspect调用:

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:我的最后一个解决方案是重新创建整个打印,通过遍历URL的所有 getter 并打印它们/将它们添加到一个对象以最终打印:

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.如果您不关心MyURL前缀并且更喜欢着色,则可以简单地返回res而不是字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM