Node: url.toString() is '[object Object]' ?!!

Created on 28 Sep 2016  路  18Comments  路  Source: nodejs/node

$ node
> url = require('url')
{ parse: [Function: urlParse],
  resolve: [Function: urlResolve],
  resolveObject: [Function: urlResolveObject],
  format: [Function: urlFormat],
  Url: [Function: Url] }
> var a = url.parse('http://xxx');
undefined
> a
Url {
  protocol: 'http:',
  slashes: true,
  auth: null,
  host: 'xxx',
  port: null,
  hostname: 'xxx',
  hash: null,
  search: null,
  query: null,
  pathname: '/',
  path: '/',
  href: 'http://xxx/' }
> a.toString()
'[object Object]'

Outrageous!
Why isn't url.toString() defined the straight way?

$ node -v
v6.3.1
url

Most helpful comment

The URL object implements a proper toString() function:

> var u = new url.URL('http://example.org/foo');
undefined
> u.toString()
'http://example.org/foo'
>

All 18 comments

Yea, this is the correct behavior because the Url is an object, but we could rewrite Url.prototype.toString as:

Url.prototype.toString = Url.prototype.format;

Please rewrite it.
[object Object] is both useless and confusing.
An URL is a string. If I pass around parsed URLs, it is much better if they convert back to a string seamlessly.

Okay, I will submit a pull request tonight, but I'm unsure if this is really necessary in core :)

a is a URL object. Thus [object Object] seems correct to me. Maybe you can use a.href if you want just want a string?

> a.href.toString()
'http://xxx/'
> typeof a.href
'string'

I think rewriting Url.prototype.toString looks like monkey patching. There is a method url.format(), toString() is not a method of Url and I see no reason to create alias by overwriting another method.

see e.g. ECMAScript spec

15.9.5.2 Date.prototype.toString ( )
This function returns a String value. The contents of the String are implementation-dependent, but are
intended to represent the Date in the current time zone in a _convenient, human-readable form._

That is my understanding of the general semantics of the toString() method.
[object Object] is clearly useless and thus has no reason to be that way.
Object implements it that way because Object is too abstract, it has no semantics of its own.
URL should have a meaningful toString() implementation.

RegExp (sec 15.10.6.4)

> /abc/.toString()
"/abc/"
> [1,2,3].toString()
"1,2,3"

et cetera

Here is some more:

> new Map().toString()
'[object Map]'
> new Set().toString()
'[object Set]'
> new Promise(() => {}).toString()
'[object Promise]'

If I pass around parsed URLs, it is much better if they convert back to a string seamlessly.

That is why url.parse() and url.format() exist.

Java's Object.toString() grows from the same root:

https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#toString()
Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method.
The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@', and the unsigned hexadecimal representation of the hash code of the object. In other words, this method returns a string equal to the value of:

getClass().getName() + '@' + Integer.toHexString(hashCode())

Returns:
a string representation of the object.

I see absolutely no point in making toString() intentionally pointless.

There are security implications to consider. If a url.format(url.parse)) round-trip is not 100% lossless, then changing Url#toString() to Url#format() may introduce vulnerabilities in applications that accidentally stringify Url objects.

With an explicit format() call, the developer will hopefully at least stop and think.

@bnoordhuis by "lossless", do you mean "side effect free" or something else ?

@gritzko That the result of s == url.format(url.parse(s)) is always true.

@bnoordhuis So, the use of Url objects is essentially discouraged. They should be treated as hashes carrying parsed results.

Well. The API hints at that indeed.

We could maybe do [object Url <href>]? I think that discourages raw passing but perhaps still is more informative.

What does the WhatWG URL object do here?

The URL object implements a proper toString() function:

> var u = new url.URL('http://example.org/foo');
undefined
> u.toString()
'http://example.org/foo'
>

@jasnell's proposal to ECMAScript 馃憤
https://github.com/tc39/proposals/pull/30

To sum it up, the status quo is:

  1. It's too late to change url.format and url.parse now
  2. You can use a well-standardized API in require('url').URL in Node.js v7+

I don't see any more we can do now, so closing.

Was this page helpful?
0 / 5 - 0 ratings