document.registerElement - Why do we need to specify both 'prototype' and 'extends'?

老子叫甜甜 提交于 2019-12-04 11:20:23

From the Custom Elements specification:

In general, the name of the element being extended cannot be determined simply by looking at what element interface it extends, as many elements share the same interface (such as q and blockquote both sharing HTMLQuoteElement).

In other words, while it may be redundant for <button> elements, it isn't redundant in general and the spec needs to support the general case.

I would argue that it isn't even redundant for <button> though, as there is nothing preventing you from doing:

var SuperButton = document.registerElement('super-button', {
  prototype: Object.create(HTMLButtonElement.prototype),
  extends: 'a'
});

To clarify Paulpro's answer: the extends creates the is= syntax. If q and blockquote both share HTMLQuoteElement, and you extend q, then you can write <q is="super-button"> but cannot write <blockquote is="super-button">.

Regarding what means to extend an a link with another element's prototype, this would create a link that does not have the appropriate functions and properties, which is bad:

See: https://jsfiddle.net/3g0pus8r/

<a is="anchor-one" href="google.com">1st link</a>
<a is="anchor-two" href="google.com">2nd link</a>

var proto1 = Object.create(HTMLAnchorElement.prototype, {
  createdCallback: {
    value: function() { 
    console.log("1st:");
    console.log(HTMLAnchorElement.prototype.isPrototypeOf(this));
    console.log(this.hostname);
    console.log(this.toString());
    }
  }
});

var proto2 = Object.create(HTMLButtonElement.prototype, {
  createdCallback: {
    value: function() {        
    console.log("\n2nd:");
    console.log(HTMLAnchorElement.prototype.isPrototypeOf(this));
    console.log(this.hostname);
    console.log(this.toString());
    }
  }
});

document.registerElement("anchor-one",{prototype:proto1, extends: "a"});
document.registerElement("anchor-two",{prototype:proto2, extends: "a"});

The result is:

1st:
true
fiddle.jshell.net
https://fiddle.jshell.net/_display/google.com

2st:
false
undefined
[object HTMLButtonElement]

However, you may still want to:

  • Extend MyOtherAnchor which in turn extends HTMLAnchorElement;
  • Extend HTMLElement and implement all the anchor interface yourself.
  • Create an anchor with a different, non-standard, interface.

Actually, its allows you to distinguish between Custom Tags declaration versus Type Extensions declaration (as suggested by Bergi's second comment), as both share the same method document.registerElement().

Type Extensions: use extends

document.registerElement( "button-v2",  { 
    prototype: Object.create( HTMLButtonElement.prototype ),
    extends: 'button'
} )

<button-v2> will continue to act as a <button> (ie keeps its semantics).

Custom Tags: don't use extends

document.registerElement( "not-button",  { 
    prototype: Object.create( HTMLButtonElement.prototype )
} )

<not-button> inherits from HTMLButtonElement interface but lost its semantics (ie won't act as a <button>)


NB: If the only reason was really because you cannot always infer an <element> from its prototype chain, an optional parameter would have been proposed to disambiguate such rare cases. Here they have choosen a common, synthetic method, which is confusing at first sight you're right!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!