This is due to an odd behavior in Chrome dev tools where the __proto__ getter will access the [[Prototype]] of the originally logged object, regardless of how nested your object is. In JavaScript, the (now deprecated) __proto__ property is a getter, which means when it is accessed, it runs a portion of code. That portion of code looks something like so:
Object.getPrototypeOf(this); // which returns this[[Prototype]]
The this in the above example is typically the object that you call .__proto__ on. For example, if you did arr.__proto__, then this would be arr, so you end up getting the prototype of the arr array as expected. In the Chrome dev tools console, things are a little different. Rather than the getter being invoked on an object like arr, it is instead invoked manually when you press (...):

So now the question is - what is the value of this when performing Object.getPrototypeOf(this); when the __proto__ getter is invoked manually? This is up to the Chrome dev tools team to decide, but it seems like the way that it behaves is that it sets the this to the originally logged object1. In your second example, that object is arr.__proto__. As a result, the getter ends up showing the [[Prototype]] of arr.__proto__ again, rather than null.
The below code snippet (see Chrome console output), is a simple example of this behavior in action:
const obj = {foo: 'bar'}; const prototypeObj = { get fake__proto__() { console.log("obj === this:", this === obj); // true: Means that `this` still refers to the original object, even when fake__proto__ is invoked on [[Prototype]] object in the console console.log("obj[[Prototype]] === this:", this === Object.getPrototypeOf(obj)); // false: Shows that `this` inside of fake__proto__ isn't the prototype object, even when `fake__proto__()` is invoked on the `[[Prototype]]` object. return this; } }; Object.setPrototypeOf(obj, prototypeObj); // Note: setPrototypeOf isn't recommended to do, but is being used here for example purposes only // View chrome console for output console.log(obj);
In the above snippet, a new object is created {foo: "bar"} which has its [[Prototype]] set to an object with a getter called fake__proto__() {}. This getter is used to see what the value of this is when invoked, so that we can get an understanding about what the native __proto__ getter might be using. When the above code is ran in Chrome, and the getter is invoked by clicking (...) on obj[[Prototype]], you get the following output:
![image to show that the fake__proto__ getter logs the original object for this even for the nested [[Prototype]] object](https://i.sstatic.net/Gsg86oOQm.png)
In the above, the two red boxes represent the same object, showing that this inside of the getter doesn't refer to the object set as the [[Prototype]] when it is invoked using (...) on the [[Prototype]] object, but rather, it refers to the originally logged object.
Unlike this, when you use arr.__proto__.__proto__, the object logged is Object.prototype, so when you invoked the __proto__ getter, the this refers to the object Object.prototype, which returns null when its prototype is accessed.
To properly walk the prototype chain, you can use nested calls to Object.getPrototypeOf():
Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(arr))); // null
1 This is just an assumption based on some observations, but might not be correct - I'm not entirely sure how chrome decides what to set the this to, but the important thing to note is that it isn't always the immediate object that the getter property appears in.
arrisArray.prototype, and its prototype isObject.prototype, and its prototype isnull. So nice one!