试图创建一个JS类(带有函数)

时间:2015-04-16 15:52:27

标签: javascript function class

我正在尝试独立地在不同区域运行我的JS代码,所以我想创建一个类并找到这个article我的问题是,我不能使用我班上的函数在我班上。

这是我的JS代码:

window.addEventListener('load', tagEditorsInit);
function tagEditorsInit() {
    var tagEditors;
    var tagLists = document.getElementsByClassName('tagList');
    for(var i = 0; i < tagLists.length; i++) {
        tagEditors[i] = new function() {
            var edit, editTag, tagList, tagInput, tagOutput, i;
            this.init = new function() {
                edit = false;
                tagList = document.querySelectorAll('[class=tagList]').item(i); //L.96/97 #1
                tagInput = tagList.querySelectorAll('[name=tagInput]');
                tagOutput = tagList.querySelectorAll('[name=tags]');
                tagInput.addEventListener('keyup', tagOnKeyPress(event.keyCode)); //13-ERROR
                tagList.addEventListener('mouseout', function() {if(tagList.ownerDocument.activeElement.parentNode !== tagList && !isHover(tagList)) {tagList.style.maxHeight = '40px';}});
                tagInput.addEventListener('focus', changeSize);
                tagInput.addEventListener('blur', changeSize);
                for(var i = 2; i < tagList.childNodes.length; i++) {
                    tagList.childNodes[i].addEventListener('click', tagOnClick);
                    tagList.childNodes[i].addEventListener('mousemove', tagOnMouseMove);
                    tagList.childNodes[i].addEventListener('mouseout', tagOnMouseOut);
                }
            };
            this.tagOnKeyPress = new function(keyCode) {
                var tagInputValue = tagInput.value.trim();
                if(tagInputValue.length !== 0) {
                    if(edit) {
                        if(keyCode === 13) {
                            edit = false;
                            editTag.style.borderColor = '#ddd';
                            tagInput.value = '';
                            return;
                        }
                        tagOutput.value = tagOutput.value.replace(editTag.innerHTML,tagInputValue);
                        newTag = editTag;
                    } else {
                        if(keyCode !== 13) return;
                        tagOutput.value = tagOutput.value + tagInputValue + ';';
                        var newTag = document.createElement('div');
                        newTag.addEventListener('click', tagOnClick);
                        newTag.addEventListener('mousemove', tagOnMouseMove);
                        newTag.addEventListener('mouseout', tagOnMouseOut);
                    }
                    newTag.innerHTML = tagInputValue;
                    tagList.appendChild(newTag);
                }
                if(!edit) tagInput.value = '';
            };
            this.tagOnClick = new function() {
                if((this.offsetWidth + getOffsetLeft(this) - event.pageX) < parseInt(this.style.backgroundSize, 10)) {
                    tagOutput.value = tagOutput.value.replace(this.innerHTML + ';','');
                    this.parentNode.removeChild(this);
                    tagInput.value = '';
                    edit = false;
                } else {
                    setEdit(this);
                }
                tagInput.focus();
            };
            this.tagOnMouseMove = new function() {
                if((this.offsetWidth + getOffsetLeft(this) - event.pageX) < parseInt(this.style.backgroundSize, 10)) {
                    this.style.backgroundSize = '16px';
                } else {
                    this.style.backgroundSize = '18px';
                }
            };
            this.tagOnMouseOut = new function() {
                this.style.backgroundSize = '18px';
            };
            this.setEdit = new function(tag) {
                edit = true;
                editTag = tag;
                tag.style.borderColor = '#297CCF';
                tagInput.value = tag.innerHTML;
            };
            this.changeSize = new function(e) {
                if(e.type === 'focus') {
                    tagList.style.maxHeight = 'none';
                } else if(e.type === 'blur' && !isHover(tagList)) {
                    tagList.style.maxHeight = '40px';
                }
            };
            this.isHover = new function(elem) {
                return (elem.parentElement.querySelector(':hover') === elem);
            };
            this.getOffsetLeft = new function(elem) {
                var offsetLeft = 0;
                while(true) { //521px over while scrolling to the right ---> (-TABLE:521px)
                    if(elem.nodeName !== 'TABLE') offsetLeft += elem.offsetLeft;
                    elem = elem.parentNode;
                    if(elem.nodeName === 'HTML') break;
                }
                return offsetLeft;
            };
        };
        //tagEditors[i].tagList = tagLists.item(i); Why isn't it working??? #1
        tagEditors[i].i = i;
        tagEditors[i].init();
    }
}

我收到此错误消息:

  

13:未捕获的ReferenceError:未定义tagOnKeyPress

     
      
  • 13 :(匿名函数)

  •   
  • 8 :(匿名函数)

  •   
  • 6:tagEditorsInit

  •   

问题:

  • 我能解决这个问题吗? ---&GT;怎么样?
  • 有更好的方法吗?

JSFiddle

谢谢! - Minding

3 个答案:

答案 0 :(得分:3)

调用以this开头的函数,该函数引用当前范围(在本例中,是&#34;类&#34的对象;您创建的,这是tagOnKeyPress函数的位置定义)。

tagInput.addEventListener('keyup', this.tagOnKeyPress(event.keyCode));

请注意,您的代码中还有其他函数调用也需要进行此更改。

这是一个从对象内部调用对象函数的简单示例:

&#13;
&#13;
function MyClass() {
    this.firstFunc = function() {
        console.log('first function');
    };
    
    this.secondFunc = function() {        
        console.log('second function calls:');
        this.firstFunc();
    };
};

var obj = new MyClass();
obj.firstFunc();
obj.secondFunc();
&#13;
&#13;
&#13;

如果查看控制台,您将看到以下输出:

  

第一个功能
  第二个函数调用:
  第一个功能

答案 1 :(得分:1)

原型方式:

function MyClass(arg1, arg2) {
  this.prop = arg1
  this.prop2 = arg2
}

MyClass.prototype.myFcuntion = function() {
  this.prop = 'changed prop';
}
MyClass.prototype.property12 = 'some property'

var instance = new MyClass('property1', 'property2');
instance.prop; // return string 'property1'
instance.myFunction();
instance.prop; // return string 'changed prop'

答案 2 :(得分:1)

好的,先解决几件事:

1.这不是创建对象的理想方法,这是您要做的事情。在这个例子中,我对它进行了一些修改,但我仍然会使用原型方法重写它。你在这里所拥有的将为每个对象实例创建这些函数,加载方式比你需要的更多。

2.在带有onKeyPress的textareas中,您不能引用tagOnKeyPress函数,该函数是tagEditor对象的一部分。它没有在公共范围内定义。

3.添加eventListeners时,除非您将函数作为处理程序返回,否则不要在处理程序的定义中执行该函数。

tagInput.addEventListener('keyup', tagOnKeyPress(event.which)); 

尝试执行&#34; tagOnKeyPress&#34; immediatley。相反,只传递函数引用,并期望&#34;事件&#34;传递给它的类型。然后,在函数中定义keyCode。

tagInput.addEventListener('keyup', this.tagOnKeyPress); //13-ERROR

this.tagOnKeyPress = function(event) {
    var keyCode = event.which;
}

4.正如其他人所指出的,当你引用函数范围内定义的函数(你的对象)时,你需要使用&#34;这个&#34;作为前缀。

我稍微更改了代码以定义&#34; TagEditor&#34;用于循环的对象。您可以将这些函数添加到TagEditor原型中,以提高性能和可扩展性。

代码:

var TagEditor = function () {
    var edit, editTag, tagList, tagInput, tagOutput, i;
    this.init = function () {
        edit = false;
        tagList = document.querySelectorAll('[class=tagList]').item(i); //L.96/97 #1
        tagInput = tagList.querySelectorAll('[name=tagInput]')[0];
        tagOutput = tagList.querySelectorAll('[name=tags]');
        tagList.addEventListener('mouseout', function () { if (tagList.ownerDocument.activeElement.parentNode !== tagList && !isHover(tagList)) { tagList.style.maxHeight = '40px'; } });
        tagInput.addEventListener('keyup', this.tagOnKeyPress); //13-ERROR
        tagInput.addEventListener('focus', this.changeSize);
        tagInput.addEventListener('blur', this.changeSize);
        for (var i = 2; i < tagList.childNodes.length; i++) {
            tagList.childNodes[i].addEventListener('click', this.tagOnClick);
            tagList.childNodes[i].addEventListener('mousemove', this.tagOnMouseMove);
            tagList.childNodes[i].addEventListener('mouseout', this.tagOnMouseOut);
        }
    };
    this.tagOnKeyPress = function (e) {
        var keyCode = e.which;
        var tagInputValue = tagInput.value.trim();
        if (tagInputValue.length !== 0) {
            if (edit) {
                if (keyCode === 13) {
                    edit = false;
                    editTag.style.borderColor = '#ddd';
                    tagInput.value = '';
                    return;
                }
                tagOutput.value = tagOutput.value.replace(editTag.innerHTML, tagInputValue);
                newTag = editTag;
            } else {
                if (keyCode !== 13) return;
                tagOutput.value = tagOutput.value + tagInputValue + ';';
                var newTag = document.createElement('div');
                newTag.addEventListener('click', tagOnClick);
                newTag.addEventListener('mousemove', tagOnMouseMove);
                newTag.addEventListener('mouseout', tagOnMouseOut);
            }
            newTag.innerHTML = tagInputValue;
            tagList.appendChild(newTag);
        }
        if (!edit) tagInput.value = '';
    };
    this.tagOnClick = function () {
        if ((this.offsetWidth + getOffsetLeft(this) - event.pageX) < parseInt(this.style.backgroundSize, 10)) {
            tagOutput.value = tagOutput.value.replace(this.innerHTML + ';', '');
            this.parentNode.removeChild(this);
            tagInput.value = '';
            edit = false;
        } else {
            setEdit(this);
        }
        tagInput.focus();
    };
    this.tagOnMouseMove = function () {
        if ((this.offsetWidth + getOffsetLeft(this) - event.pageX) < parseInt(this.style.backgroundSize, 10)) {
            this.style.backgroundSize = '16px';
        } else {
            this.style.backgroundSize = '18px';
        }
    };
    this.tagOnMouseOut = function () {
        this.style.backgroundSize = '18px';
    };
    this.setEdit = function (tag) {
        edit = true;
        editTag = tag;
        tag.style.borderColor = '#297CCF';
        tagInput.value = tag.innerHTML;
    };
    this.changeSize = function (e) {
        if (e.type === 'focus') {
            tagList.style.maxHeight = 'none';
        } else if (e.type === 'blur' && !isHover(tagList)) {
            tagList.style.maxHeight = '40px';
        }
    };
    this.isHover = function (elem) {
        return (elem.parentElement.querySelector(':hover') === elem);
    };
    this.getOffsetLeft = function (elem) {
        var offsetLeft = 0;
        while (true) { //521px over while scrolling to the right ---> (-TABLE:521px)
            if (elem.nodeName !== 'TABLE') offsetLeft += elem.offsetLeft;
            elem = elem.parentNode;
            if (elem.nodeName === 'HTML') break;
        }
        return offsetLeft;
    };
};
function tagEditorsInit() {
    var tagEditors = [];
    var tagLists = document.getElementsByClassName('tagList');
    for (var i = 0; i < tagLists.length; i++) {
        var tagEditor = new TagEditor();
        tagEditor.tagList = tagLists.item(i); // Why isn't it working??? #1
        tagEditor.i = i;
        tagEditor.init();
        tagEditors.push(tagEditor);
    }
}
window.addEventListener('load', tagEditorsInit);

现在,我承认我不会在任何地方使用Prototype方法。有时候,我会编写一个我需要在特定实例中使用的小对象,并且我不会像使用复杂对象那样处理它。但是,在编写jQuery插件或自定义应用程序的特殊脚本时,Prototype方法更容易阅读,分解和使用。

这究竟意味着什么?原型方法使用对象类型定义函数,而不是每次创建对象的实例时定义。为了举例说明使用上面的代码,每次创建TagEditor时,该tagEditor对象都会为该特定的tagEditor对象重新定义所有这些函数。如果你能够扩展或打开单个对象,就像阅读为每一个对象定义的所有函数。

使用原型方法,它或多或少基于类,就像C ++或C#这样的面向对象的lang会有。每当你打电话给 &#34; tagOnKeyPress&#34;函数,它使用与TagEditor类型相关联的函数。不是用&#34; tagEditor&#34;定义的那个。 TagEditor类型的对象。简而言之,该函数仅定义一次,并继承对&#34; tagEditor&#34;中定义的属性的访问权限。那种对象。

如果我没有把这个解释与你混淆,请查看这篇MDN文章,该文章很好地展示了所有这些的例子以及它的不同之处:

更新此更新是对您的评论和小提琴的回应。我刚刚通过你的小提琴进行了一些修改。希望你能看到我改变了什么。以下是一些额外的评论

1. this.tagInput的定义需要引用一个节点,而不是NodeList。有几个我认为你期望单个节点但是得到长度为1的NodeList。要引用实际的DOM元素来分配EventListener,你只需要指定NodeList的0索引。

2.当您将函数绑定为处理程序时,除非返回函数,否则不想执行该函数。上面的子弹3显示了一个这样的例子。在函数名称(myMouseHandler())之后添加括号时,它会在此时执行该函数。它不会等到偶数发生。

3.当您在特定范围内工作时,您可以定义局部变量以简化对象属性的使用。例如,如果您使用&#34; this.tagList&#34;很多,你可能厌倦了打字&#34; this.tagList&#34;到处。定义它时,可以像这样分配属性和局部变量:

var tl = this.tagList = document.getElementsByClassName('tagList').item(tagListID);

然后你可以使用&#34; tl&#34;在该范围内。

this.tagOuput.value = tl.value;

4.使用Prototype分配事件处理程序时,您仍然需要一种方法来引用您正在使用的主对象。 eventListener绑定中的匿名函数提供了一种在需要时执行此操作的简便方法。

// function is the actual handler. e = event, this = element, te = tagEditor
tagInput.addEventListener('mouseout', function(e) { te.tagOnClick(e, this); });

我试着清理你的小提琴并开始工作,我猜你正在尝试。您可能需要更多,但这可能为您提供更清晰的工作位置。

小提琴:https://jsfiddle.net/938z8x98/13/