简体   繁体   中英

Node's console is not showing all the object properties ... is this expected behavior?

I did a

  console.log(myURL);

and did not see the extension property

  console.log(myURL.extension);

but if I log it on it's own it correctly shows the value.

found is a URL object created as such:

  const url = require('url');
  let myURL = new URL(test);

the missing property was added as such:

  myURL.extension = test.split('.').pop();

The output looks like this:

URL {
  href: 'https://www.imdb.com/favicon.ico',
  origin: 'https://www.imdb.com',
  protocol: 'https:',
  username: '',
  password: '',
  host: 'www.imdb.com',
  hostname: 'www.imdb.com',
  port: '',
  pathname: '/favicon.ico',
  search: '',
  searchParams: URLSearchParams {},
  hash: ''
}

Example code:

const url = require('url');
const test = 'https://www.imdb.com/favicon.ico';
let myURL = new URL(test);
myURL.extension = test.split('.').pop();
console.log(myURL);

The reason for this behavior is because the prototype of URL defines autil.inspect.custom override. In Node.js v12.11.0 for example, it's defined like this:

> console.log(myURL[util.inspect.custom])

[inspect.custom](depth, opts) {
  if (this == null ||
      Object.getPrototypeOf(this[context]) !== URLContext.prototype) {
    throw new ERR_INVALID_THIS('URL');
  }

  if (typeof depth === 'number' && depth < 0)
    return this;

  const ctor = getConstructorOf(this);

  const obj = Object.create({
    constructor: ctor === null ? URL : ctor
  });

  obj.href = this.href;
  obj.origin = this.origin;
  obj.protocol = this.protocol;
  obj.username = this.username;
  obj.password = this.password;
  obj.host = this.host;
  obj.hostname = this.hostname;
  obj.port = this.port;
  obj.pathname = this.pathname;
  obj.search = this.search;
  obj.searchParams = this.searchParams;
  obj.hash = this.hash;

  if (opts.showHidden) {
    obj.cannotBeBase = this[cannotBeBase];
    obj.special = this[special];
    obj[context] = this[context];
  }

  return inspect(obj, opts);
}

You could override this behavior and add the extension property as a getter to the URL class's prototype if you really cared about the output format:

const { URL } = require('url');
const { inspect } = require('util');

Object.defineProperty(URL.prototype, 'extension', {
  enumerable: true,
  configurable: true,
  get() { return this.pathname.split('.').pop(); }
});

URL.prototype[inspect.custom] = function(depth, opts) {
  if (typeof depth === 'number' && depth < 0) return this;

  const keys = Object.keys(URL.prototype).filter(key => typeof this[key] !== 'function');
  const obj = Object.create({ constructor: URL });
  Object.assign(obj, ...keys.map(key => ({ [key]: this[key] })));
  return inspect(obj, opts);
};

and then your output format will look like this:

> new URL('https://www.imdb.com/favicon.ico')
URL {
  href: 'https://www.imdb.com/favicon.ico',
  origin: 'https://www.imdb.com',
  protocol: 'https:',
  username: '',
  password: '',
  host: 'www.imdb.com',
  hostname: 'www.imdb.com',
  port: '',
  pathname: '/favicon.ico',
  search: '',
  searchParams: URLSearchParams {},
  hash: '',
  extension: 'ico'
}

However, if you don't care that much then you can just accept that the output format you see is the expected behavior, and you can access the extension property just as you normally would on any other object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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