Repository navigation
Native class of global changed in Node v7 #9274
Description
Activity
Digging in
/cc @nodejs/ctc
Reacted by AthanI'm not sure if this is a change that we made or if it came from the v8 update.
I can start bisecting this
Reacted by Athan- addedv8 engineIssues and PRs related to the V8 dependency.Issues and PRs related to the V8 dependency.
on Oct 25, 2016 It's a change that comes from V8. We don't muck around with the global object's prototype. Example with v6:
> vm.runInNewContext('Object.prototype.toString.call(this)') '[object global]'With v7:
> vm.runInNewContext('Object.prototype.toString.call(this)') '[object Object]'/cc @nodejs/v8
I can confirm that this change came in somewhere between 8a24728...96933df
which leads me to believe this came with the V8 upgrade
Reacted by AthanBtw, this can be fixed with
global[Symbol.toStringTag] = 'global'. I’m not sure whether that should be applied to any of the objects generated by thevmmodule, though.Can, but I don't know if we should. If the use case is feature detection, then sniffing for
processseems like a better choice in the first place.@bnoordhuis A use case is feature detection. Another time when the internal class matters is when type checking or handling special cases; e.g.,
var toString = Object.prototype.toString; function foo( bar ) { var nativeClass = toString.call( bar ); if ( nativeClass === '[object global]' ) { // ...do something... } else if ( nativeClass === '[object process]' ) { // ...do something... } else { // ...do something else } }
And specifically re: environment detection: usually checking the internal class is combined with other checks including
processin order to more confidently claim an environment is Node.Regardless, the change introduces an (unintended) inconsistency between Node versions.
I think I agree; if something like this is changed, it should be conscious decision we make.
(I also agree that sniffing for
processseems like the best way to detect Node.)I would go a step further and say that checking that
process.versions.nodeexists (checking each property in the path exists of course) and is a non-empty string is all that is really needed.@kgryte My point is more that checking for this particular behavior is not a very good indicator of a node.js runtime because you'd see the same behavior in, say, plv8, or any V8-backed runtime that doesn't override the default.
Reacted by Anna HenningsenJust to clarify and keep things focused: this issue is not about the right way to detect a Node environment, but about the fact that an unintended breaking change was introduced in Node v7 due to how V8 reports the internal class of
global.Reacted by Anna Henningsen, Prince John Wesley and Jon Schlinkert15 remaining items
I think this is the change that caused this:
https://codereview.chromium.org/2080243003V8 is following the ES6 spec here, which does not leave much room for interpretation:
https://tc39.github.io/ecma262/#sec-object.prototype.tostringIn d8, we indeed define the toStringTag for the global object to be "global". In Chrome, window[Symbol.toStringTag] is set to "Window". Maybe this is the path node should take as well?
Reacted by Athan, F. Hinkelmann and Sam RobertsReacted by Jordan Harband and dnalborczyk@hashseed Which path do you suggest node take, setting it to
global, or setting it toWindow?To global to mimic the old behavior.
This proposals https://github.com/tc39/proposal-global (stage 3) intention is to unify the 'global' object independent of the runtime environment. The name for such an object is 'global' (the same as node.js is currently using, as supposed to self, System.global etc.). Therefore, I suspect that if the proposal is being accepted, and browsers implement it, global.toString() will likely return - according to the spec - '[object Object]' as well.
If we revert this now to mimic pre-v7-behavior, we might need to revisit it again in the future to revert the reverted, if we want consistency between environments.
@ljharb Is that assumption correct?
The JS spec will continue to not contain or require (nor prohibit, it must be noted) that
globalhave aSymbol.toStringTagdefined.So, despite my belief that there should be no such behavior, I must still acknowledge that there's no spec compliance issue here, either way. Browsers may and will continue to return
[object Window], and node can choose to return whatever it wants.I also don't think there's a compatibility issue here either way, because with the advent of ES6 and
Symbol.toStringTag, nobody should ever be relying on the output ofObject.prototype.toStringever again for anything but debugging, and to do so is to make your code brittle.Thanks @ljharb
I should have been more specific, I meant the spec regarding https://tc39.github.io/ecma262/#sec-object.prototype.tostring referred above.
@dnalborczyk that spec says that if
global[Symbol.toStringTag] === 'global', thatObject.prototype.toString.call(global)should return'[object global]'@ljharb Never using
Object#toStringis an unrealistic expectation. Far too much code which already exists in the wild usesObject#toStringto check for a whole variety of things, not just'[object global]'. And this is not going to be fixed or stopped. That this would lead to "brittle" code should have been (and probably was) considered during the specification phase.My understanding is that one motivation, and intended byproduct, of
Symbol.toStringTagwas to allow people to customize the output ofObject#toStringand, thus, enable another means of identifying user defined classes. For example,if ( Object.prototype.toString.call( foo ) === '[object MyVerySpecialClass]' ) { // I've identified an instance of MyVerySpecialClass! } else { // Not an instance of MyVerySpecialClass }That this feature can also be used for ill is not necessarily a reason to avoid using the behavior. And people will use this behavior for identifying their own custom class instances, just as Chrome sets
window[Symbol.toStringTag] = "Window". That Node may want to "customize" its own environmentalglobalseems a realistic possibility.Truth is, similar to modifying a built-in prototype (that you can do so, by your definition, would make using prototypical methods "brittle" and to be avoided whenever possible, including for builtins!) modifying a foreign object's
toStringTagshould not be encouraged. But...this should not stop those who define the environment or introduce their own objects from customizing the output ofObject#toString, particularly if it means easier identification of said objects, or, in this case, maintaining backward compatibility.I think we can safely assume that pre-ES6 code that assumes String(global)=="[object global]" won't interfere with toStringTag, since the latter is also an ES6 feature.
Reacted by Anna Henningsen@kgryte none the less, it's the reality since ES6 erased the unforgeability of
Object#toString.Certainly the case you're describing - as a publicly available opt-in, is a fine use of it. But using it as a brand check is no longer reliable, no matter how much code is doing it.
@hashseed except that in newer environments,
global = { [Symbol.toStringTag]: 'global' };can make that code go down unintended paths.Sure. We would have to weigh cases that rely on the old behavior against ones that use toStringTag for other purposes.
- added a commit that references this issue
on Nov 2, 2016 Just noting something curious, but I'm in Node 8 and some functions that I create with
new Functionappear as[object global]in the console, and.bind()method is missing, which is strange.Look at the strange output I see when debugging:
Not sure how to reproduce, otherwise I'll open a new issue.Made an issue with repro: #19651- added a commit that references this issue
on Jul 27, 2026

In Node.js version
<= 6.x.x,In Node.js version
7.0,Based on the changelog, this is not listed as a notable and/or breaking change. Why did the internal class change and is this a permanent/intentional change?
Background: one reason why this is a notable change is that environment sniffers (i.e., packages which try and detect if the runtime is Node versus, say, a browser) commonly use the internal class of
globalas means to identify a Node environment.