Skip to content

Commit

Permalink
Node.js util.format('%s') breaking change bug
Browse files Browse the repository at this point in the history
The documentation says that util.format('%s', obj) will call String(obj) iff obj has a user-defined .toString method, but in v12.12.0 it only calls String(obj) if either obj or obj.constructor.prototype has an own property named toString, causing inherited toString implementations to be ignored.

Submitted as nodejs/node#30333
  • Loading branch information
cpcallen committed Nov 8, 2019
1 parent 61b38b5 commit 6191e2e
Showing 1 changed file with 41 additions and 0 deletions.
41 changes: 41 additions & 0 deletions node/format-bug.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* The documentation says that util.format('%s', obj) will call
* String(obj) iff obj has a user-defined .toString method, but in
* v12.12.0 it only calls String(obj)
*
* Submitted as https://github.com/nodejs/node/issues/30333
*/

// ES6 subclassing:
class A {
toString() {
return 'custom A';
}
}

class B extends A {
}

// ES5 subclassing:
function C() {
};

C.prototype.toString = function() {
return 'custom C';
}

function D() {
C.call(this);
}

D.prototype = Object.create(C.prototype);
// What if we forget to set the .constructor?
// D.prototype.constructor = D;

console.log('%s', new A()); // expected/actual: custom A
console.log('%s', new B()); // expected: custom A / actual: B {}
console.log('%s', new C()); // expected/actual: custom C
console.log('%s', new D()); // expected/actual: custom C (!)

// Fix forgotten .constructor:
D.prototype.constructor = D;
console.log('%s', new D()); // expected: custom C / actual: D {}

0 comments on commit 6191e2e

Please sign in to comment.