我可以继承DOM类吗?

时间:2011-04-17 21:34:53

标签: javascript prototype

我想知道我是否可以创建HTMLDivElement的子类。像这样。

MyDivElement.prototype.pickColor = function()
{
    return this.picked;
}
function MyDivElement()
{
    this = new HTMLDivElement();
    this.picked = 'unknowd';
}
alert(this.picked); // print: 'unkowd'

这是(类似的)这可能吗? 如果没有,实现这一目标的最佳方法是什么?

4 个答案:

答案 0 :(得分:6)

__proto__公开且可变的浏览器中,您可以使用子类DOM元素。它看起来像这样:

function CustomEl () {
    var el = document.createElement('div')
    el.__proto__ = CustomEl.prototype
    return el
}
CustomEl.prototype.__proto__ = HTMLDivElement.prototype

我还在jsFiddle上详细介绍了它。不幸的是,虽然IE和Opera不允许__proto__访问,并且据我所知,将来也没有计划。

答案 1 :(得分:2)

new HTMLDivElement();在Chrome中引发了TypError "Illegal constructor" - 所以这是不可能的。

更新:我已在其他当前浏览器中测试过,它们会抛出各种类型的错误 - 但它们都会抛出。


实际上,这可行:

function MyDivElement() {
    this.picked = 'unknowd';
}

MyDivElement.prototype = document.createElement('div');

var mydiv = new MyDivElement();

但我不确定你如何使用这种模式...

答案 2 :(得分:1)

在某些浏览器中,您可以扩展原型,在其他浏览器中,可以扩展原型。我会让你猜你不能的。 :-)这与扩展DOM元素并不完全相同,但它确实允许你做一些你可能想要那个设施的东西的子集。问题是,DOM元素不是真正的JavaScript实体;它们只是运行时系统提供的模拟。 (也许有一天,所有的jsdom工作都会实现。)

好吧我会告诉你有问题的浏览器:IE根本不喜欢它。然而其他人呢。如果你曾经看过Prototype库,那么当你忘记Prototype-ize一个DOM元素引用的时候,你会偶然发现这个事实的表现,通过令人烦恼的IE-only bug。

(IE9可能会有所不同,但我对此表示怀疑。)

这是在jsfiddle测试过的简单易事的事情。

答案 3 :(得分:1)

我正在试验这一点。一个很大的困难是您需要文档的上下文来创建元素。您可以使用window.document作为默认设置,但这很无聊。

这是我正在进行的POC:

function CustomNode(type, parent) { 
    if (type instanceof Node) {
        // Decorate a preexisting node appropriately if called that way.
        if (arguments.length === 2 && type.ownerDocument !== parent) {
            // Import the node if it's not owned by the requested document.
            type = parent.importNode(type, true);
        }
        return Object.assign(type, this.__proto__);
    }
    //Normal flow, e.g., new CustomNode("div");
    var d = document;
    if (parent) {
        // Alt document flow, e.g., new CustomNode("div", xmlDoc);
        if (parent.nodeType === 9) {
            d = parent;
        } else {
            // Support for new CustomNode("div", parentElement);
            //  This doesn't append the element, just makes sure 
            //  the documents match
            d = parent.ownerDocument;
        }
    }
    var inst;
    // Creation flags
    if (type[0] === '#') { //text
        inst = d.createTextNode(type.substr(1));
    } else if (type[0] === '?') { //Processing instruction
        type = type.substr(1).split(' ');
        inst = d.createProcessingInstruction(type.shift(), type.join(' '));
    } else if (type[0] === '[') { // CDATA
        inst = d.createCDATASection(type.substr(1));
    } else if (type[0] === '/') { // Comment
        inst = d.createComment(type.substr(1));
    } else { //Everything else gets an element.
        inst = d.createElement(type);
    }
    // DE-COR-ATE
    Object.assign(inst, this.__proto__);
    return inst;
}
// Decorator for customized NodeLists; probably inefficient.  Decorates
//   contents with CustomNode
function CustomNodeList(list) {
    var Self = this.constructor,
        CNode = this.Node;
    return Object.assign([].map.call(list, function (node) {
        return new CNode(node);
    }), this.__proto__);
}
CustomNodeList.prototype = {
    // so we know how to wrap...
    Node: CustomNode,
    text: function () {
        return this[0].textContent;
    }
};


CustomNode.prototype = {
    // So we know how to decorate NodeLists
    NodeList: CustomNodeList,
    // So we know how to decorate Nodes
    Node: CustomNode,
    // Easy make-and-attach
    new: function (type, attach) {
        var CNode = this.Node;
        var ret = new CNode(type, this.ownerDocument);
        if (attach) {
            this.appendChild(ret);
        }
        return ret;
    },
    // NodeLists with ES5 iterators!
    find: function () {
        var CNodeList = this.NodeList;
        return new CNodeList(this.querySelectorAll.apply(this, arguments));
    },
    kids: function () {
        var CNodeList = this.NodeList;
        return new CNodeList(this.childNodes);
    }
};

介意,这可能是一个坏主意:这些函数的相同范围内的所有内容(包括元素本身)将永远不会收集垃圾,因为大多数浏览器中的GC都是愚蠢的它涉及引用对象的元素。因为这个原因,我永远不会将它用于制作:它是一种直接的内存泄漏。