问题
Consider I want to extend the native button element, and create my own super-button element. As I know, it must follow the following pattern:
var SuperButton = document.registerElement('super-button', {
prototype: Object.create(HTMLButtonElement.prototype),
extends: 'button'
});
It looks strange to me - doesn't the prototype and extends parameters say the same thing? If I explicitly say that my super-button use the HTMLButtonElement prototype, why do I also need to specify that it extends the button element? isn't it redundant? For me it looks like exactly the same information.
回答1:
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'
});
回答2:
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
MyOtherAnchorwhich in turn extendsHTMLAnchorElement; - Extend
HTMLElementand implement all the anchor interface yourself. - Create an anchor with a different, non-standard, interface.
回答3:
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!
来源:https://stackoverflow.com/questions/36561712/document-registerelement-why-do-we-need-to-specify-both-prototype-and-exten