【问题标题】:Why does my HTML constructor object return [object Object] instead of [HTMLElementElement]?为什么我的 HTML 构造函数对象返回 [object Object] 而不是 [HTMLElementElement]?
【发布时间】:2014-05-04 04:41:30
【问题描述】:

背景

我正在尝试制作一个完全纯 JavaScript GUI 来创建用于学习目的的 HTML 内容。文件中唯一真正的 html 将是一个 <script></script> 元素。我想我快完成了。

我创建了一个自定义 HTML 元素构造函数,但是当我创建一个对象时,当我执行 alert(whatever); 时,显示的是 [object Object] 而不是 [object HTMLWhateverElement](参见下面的示例)。我认为这会阻止我将子元素附加到父元素时,它们都是由构造函数创建的。

主要问题

如果我可以让 HTML 实例附加到 HTML 标签element 实例,那我会非常高兴。

构造函数

function element(tagName) {
    var element = document.createElement(tagName);

    this.setText = function(elementText) {
        if(element.childNodes.length < 1) {
            var text = document.createTextNode(elementText);
            element.appendChild(text);
        } else {
            element.childNodes[0].nodeValue = elementText;
        }
    }

    this.removeText = function() {
        element.removeChild(element.childNodes[0]);
    }

    this.setAttribute = function(attribute,value) {
        element.setAttribute(attribute,value);
    }

    this.removeAttribute = function(attribute) {
        element.removeAttribute(attribute);
    }

    this.appendTo = function(parent) { // Works but not on element instances of the constructor
        parent.appendChild(element);
    }

    this.details = function(){
        alert(
            "Type: " + element + 
            "\n\"typeof\": " + typeof(element) // Shouldn't need this right?
        );
    }
}

示例

ul = new element("ul");
ul.appendTo(body); // works fine if BODY is actually an HTML tag

alert(body); // gives me [object HTMLBodyElement] :)
alert(ul); // gives me [object Object] >(

li = new element("li"); // works :)
li.setText("list item text"); // works :)
li.appendTo(ul); // doesn't work >(

如果我能弄清楚如何将 JavaScript 创建的(子)elements 附加到其他 JavaScript 创建的(父)elements,我会很高兴的。我认为这与构造函数的实例化元素的返回值有关。

编辑

1) 可能的答案

@carter-sand 谢谢。 添加一个新的this.appendChild 方法有效,但重新发明了轮子 HTML 对象的内置 appendChild 方法。

2) 可能的答案

@s4mok 感谢您的提示。 将 var element 更改为 this.elem 有效,但会创建一个 时髦的界面:

li.appendTo(ul.elem); 

对比

li.appendTo(ul);

我正在尝试模拟私人成员。

两个答案都有效,但都没有返回值 [object HTMLWhateverElement] 当我这样做时:

alert(li);

有没有办法获得上述所有好处?

【问题讨论】:

  • 请注意,因为您在构造函数中添加了所有方法(当它们应该在其原型上时),所以对 element 的引用保存在闭包中。
  • @RobG,感谢您的反馈。是否可以在构造函数中向原型添加方法以模拟类声明?将 element 保持在闭包中是不是很糟糕?
  • 向构造函数的原型添加方法是原型继承的工作原理。将 element 保留在闭包中是可以的(它有点模拟私有成员),但您可能希望将其设为公共成员以便于访问。
  • 谢谢大家。您非常乐于助人,我从您的所有回复中学到了很多。对于其他读者,我选择了@Andrew Sellenrick 的答案,因为它完整而明确地回答了这个特定问题,但是如果您像我一样在 JavaScript 中的构造函数中苦苦挣扎,所有其他响应者也提供了非常有用的信息。

标签: javascript html object constructor return-type


【解决方案1】:

如果我运行您的示例,我会在控制台中注意到以下错误消息:

Uncaught TypeError: Object #<element> has no method 'appendChild'

这是因为您的自定义 element 实例没有您在 appendTo 中使用的 appendChild 方法。您需要在构造函数中添加一个,如下所示:

this.appendChild = function(child) {
    element.appendChild(child);
}

【讨论】:

  • 谢谢,但有没有办法在不重新发明轮子的情况下做到这一点?
【解决方案2】:
ul = new element("ul");

上面一行是实例化函数 element() 并且分配给 ul 的实例是一个 object 而不是 HTMLWhateverElement

ul.appendTo(body); // works fine if BODY is actually an HTML tag

以上方法有效,因为您的代码是:

this.appendTo = function(parent) { // Works but not on element instances of the constructor
    parent.appendChild(element);
}

而父元素是 body 和一个 HMTL 元素,并且有一个方法 appendChild,而您要附加的元素是该行中的元素:

var element = document.createElement(tagName);

为什么下面的代码不起作用?

li = new element("li"); // works :)
li.setText("list item text"); // works :)
li.appendTo(li); // doesn't work >(

这个问题的答案首先是li不是HTML元素的代码

this.appendTo = function(parent) { // Works but not on element instances of the constructor
    parent.appendChild(element);
}

将失败,因为实例 li 不是 html 元素,而是函数 element() 的对象实例

此代码中的另一个错误是您有一个循环 li.appendTo(li);如果您检查代码,则将其作为子 li 附加到自身。类似于悖论或循环依赖。

编辑:

我的建议:

  • 首先,可能在函数元素中更改“元素”的名称以避免混淆。 :D
  • 公开 var element = document.createElement(tagName); 以便您可以从方法 appendTo 的参数 parent 访问它这将允许您使用 parent.getTheExposedElement().appendChild ()

【讨论】:

  • 谢谢,这可行,但提供了一个时髦的界面。 li.appendTo(ul.element);
  • 而不是li.appendTo(ul.element); 使用li.appendTo(ul); 并在appendTo 函数内,以parent.element.appendChild(element); 访问元素
  • 我刚刚看到@Andrew Sellenrick 的回答,我认为这是根据您的要求来做的方法
【解决方案3】:

您的函数在使用“new”关键字创建时返回一个自身的实例 [object Object]。您可以通过专门返回您的元素来覆盖它。但是,您需要将“this”改为您的元素,因为“this”指的是 function 新实例。同样如建议的那样,如果您将“元素”更改为“newElement”之类的其他内容,则可能不会那么混乱。

function element(tagName) {
    var element = document.createElement(tagName);

    element.setText = function(elementText) {
        if(element.childNodes.length < 1) {
            var text = document.createTextNode(elementText);
            element.appendChild(text);
        } else {
            element.childNodes[0].nodeValue = elementText;
        }
    }

    element.removeText = function() {
        element.removeChild(element.childNodes[0]);
    }

    element.setAttribute = function(attribute,value) {
        element.setAttribute(attribute,value);
    }

    element.removeAttribute = function(attribute) {
        element.removeAttribute(attribute);
    }

    element.appendTo = function(parent) { // Works but not on element instances of the constructor
        parent.appendChild(element);
    }

    element.details = function(){
        alert(
            "Type: " + element + 
            "\n\"typeof\": " + typeof(element) // Shouldn't need this right?
        );
    }
    return element;
}


ul = new element("ul");
ul.appendTo(document.body); // works fine if BODY is actually an HTML tag

alert(document.body); 
alert(ul); 

li = new element("li");
li.setText("list item text"); 
li.appendTo(ul); 

【讨论】:

  • 是的,是的,是的!这正是我一直在寻找的。这允许实例化的返回值为[object HTMLWhateverElement],并且HTML DOM 元素的所有方法和属性都可以被实例访问,包括.appendChild();。这完全回答了这个问题。现在我只需要了解更多关于原型继承的知识,就像@RobG 提到的那样。
  • 值得注意的是,现在用 new 调用函数是没有意义的,因为新实例不用于任何事情,也不返回。它还覆盖了 HTML 元素的标准方法(例如 setAttribute),并添加了可能与未来添加到 DOM 的 NodeHTMLElement 接口相冲突的方法。这就是为什么像 jQuery 这样的库将元素的引用作为对象(“jQuery 对象”)的属性,而不是扩展实际元素本身。
猜你喜欢
  • 1970-01-01
  • 2021-01-29
  • 2021-04-15
  • 1970-01-01
  • 1970-01-01
  • 2013-05-05
  • 2019-10-18
  • 1970-01-01
  • 2011-07-27
相关资源
最近更新 更多