8

Note: I've searched for this error, but everything I've found was about calling functions. I'm not calling any function. I'm just trying to access a property.


I get the error when I execute this simple code:

var a = document.getElementById("something");
var b = Object.create(a);
console.log(b.baseURI) //Throws error with any property of a
<p id="something">Hi! I exist just for demo purposes. This error can occur with any element.</p>

I have no idea of why this happens. The code works fine if I try to get the property from the prototype of b...

var a = document.getElementById("something");
var b = Object.create(a);
console.log( Object.getPrototypeOf(b.baseURI) ) //Works

... and also using a normal object.

var a = {foo: "Foo!"};
var b = Object.create(a);
console.log(b.foo) //Works

Why does this happen? It makes no sense to me. MDN says:

When trying to access a property of an object, the property will not only be sought on the object but on the prototype of the object, the prototype of the prototype, and so on until either a property with a matching name is found or the end of the prototype chain is reached.

The prototype chain of b (in the first example) is:

HTMLParagraphElement --> HTMLParagraphElement (the actual element object) --> HTMLParagraphElement --> HTMLElement --> Element --> Node --> EventTarget --> Object --> null

(Proof)

EDIT: Note how the 1st object in the proto chain is a HTMLParagraphElement. This is normal, so that's not the problem. (Image)

The problem (i think) is that the proprieties get kinda copied to the main b object and not just to b's prototype. This means that the browser founds a matching name right in the first object and tries to access it, but it throws an error. (Image; clicking the (...) results in error).

However, I still don't understand why this happens nor why the error is thrown.

D. Pardal
  • 6,173
  • 1
  • 17
  • 37
  • Oh, and also, I've posted a similar question. This one is different, as I just want to know **why** this happens. – D. Pardal Apr 11 '18 at 20:31
  • You are "calling" a getter: `.baseURI`. And you're calling it on `b`, which is not a DOM element, unlike `a`. – Bergi Apr 11 '18 at 20:57
  • Possible duplicate of [put HTML element in prototype chain?](https://stackoverflow.com/q/48920586/1048572) – Bergi Apr 11 '18 at 21:03
  • No, `Object.create` does not copy anything. It just make the properties accessible through inheritance. – Bergi Apr 12 '18 at 11:40
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/168830/discussion-between-d-pardal-and-bergi). – D. Pardal Apr 12 '18 at 12:08
  • You don't seem to understand the diference between the DOM and JavaScript. You've illegally used a JavaScript object creation method `Object.create( a );` to create\clone a desired DOM element! The error is correct that's a wrong object Type. – Bekim Bacaj Jul 11 '20 at 09:22
  • @BekimBacaj This is an old question. Now that I've I realized the problem, that some answers didn't explain: DOM objects are also JavaScript objects. The properties on DOM objects have getters, that are invoked with the `this` context object set to the object they are invoked in, but because `this` is not a DOM object, they fail. – D. Pardal Jul 11 '20 at 10:23

2 Answers2

3

This behavior is caused by the implementation of the specification. These DOM nodes are so-called 'platform objects' and the way they implement getters is slightly different from 'normal' javascript.

In short: they can not be extended without extra work.

var a = document.getElementById("something");
var b = Object.create(a);

When the baseURI of b is accessed, its this points to b which is not a valid 'platform object'. This causes the Illegal invocation error. Accessing it through the prototype does work because then its this points to the prototype which is a valid 'platform object'.

This comment on an issue of Chrome explains it in more detail and also supplies a workaround if you really need it: https://bugs.chromium.org/p/chromium/issues/detail?id=495437#c7

EECOLOR
  • 11,184
  • 3
  • 41
  • 75
  • or simply put you cannot use JavaScript object creation methods to create DOM Elements. Becasue DOM objects, are not only of a different type, but also of a completely different kind. – Bekim Bacaj Jul 11 '20 at 09:25
  • @BekimBacaj could you explain what you mean with 'different type' and 'different kind'? I think I don't know what 'kind' means. – EECOLOR Dec 02 '20 at 21:33
  • 1
    It means that the typeof `div` is not a JS Object but a HTMLDivElement and also of a different kind because DOM is not JavaScript. – Bekim Bacaj Dec 03 '20 at 19:47
0

DOM objects are implemented very specially in browsers. When you copy one of them using a generic function like Object.create(), the result isn't linked into the DOM the same way as the original. Many of the properties need to access the DOM, so you get an error when you try to access these properties in the copy.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    It's no reason. This can not explain why `Object.getPrototypeOf(b, "baseURI")` works? – terry.qiao Apr 12 '18 at 02:27
  • @terry.quiao is right. This doesn't fully explain why prototypes are so messed up. I'm going to edit the post around 7:00 GMT (I hope) and add a thing that I've forgot to mention. – D. Pardal Apr 12 '18 at 08:12
  • 1
    @terry.qiao What's that? `Object.getPrototypeOf` takes only a single parameter. – Bergi Apr 12 '18 at 08:22
  • @Bergi You are correct. It should be `Object.getPrototypeOf(b.baseURI)` and I find it does not work on my Chrome. (So, OP was wrong?) – terry.qiao Apr 12 '18 at 08:45
  • 1
    @terry.qiao Maybe `Object.getPrototypeOf(b).baseURI`? – Bergi Apr 12 '18 at 09:10