jQuery方法中的奇怪的npe

时间:2011-05-05 13:14:40

标签: jquery

我有这个jQuery方法,如果我在找到了元素.singlePaneOfGlassBlock的页面上,可以正常工作。

function replaceRightClickIcefacesMethod() {
        //I only want this to run on IE for now, but the content 
        //is prepared to run on other browsers too
        if (jQuery.browser.msie) {
            var elem = jQuery(".singlePaneOfGlassBlock"), oldName = elem
                    .attr("oncontextmenu"), fn = String;

            //IE returns function instead of string so let's try to take the string
            //in the right way
            if (typeof oldName == "function") {
                oldName = elem[0].getAttributeNode("oncontextmenu").value,
                        fn = Function;
            }
            //do the replace
            oldName = oldName.replace('Ice.Menu.contextMenuPopup',
                    'contextMenuPopupUpdated');
            //change oncontextmenu with the new value
            jQuery.each(elem, function() {
                this.setAttribute("oncontextmenu", fn(oldName));
            })
        }
    }

但它错误地出现了这个错误:

`'undefined' is null or not an object`

在尝试进行替换的行上,如果我在其他缺少这些元素类型的页面上...

我在添加之前添加了一个检查以查看它是否为null或者是否包含该字符串,但它仍然失败:

if (jQuery(oldName).length || oldName.indexOf("Ice.Menu.contextMenuPopup") != -1) {
        oldName = oldName.replace('Ice.Menu.contextMenuPopup',
                'contextMenuPopupUpdated');
        jQuery.each(elem, function() {
            this.setAttribute("oncontextmenu", fn(oldName));
        })
    }
你能给我一个解决方案吗?

感谢。

UPDATE :当我问一个解决方案时,我只是问如何纠正这种方法,以便在找不到那种类型的元素时不运行?

3 个答案:

答案 0 :(得分:2)

  

你能给我一个解决方案吗?

我不确定 - 对于初学者,请格式化您的代码,以便更清楚它应该做什么。 看起来像,就像在if条件之后你可能有一对丢失的大括号。

至少,使用逗号分隔的表达式来实现两个赋值 - 将该块放在大括号中并正确地拆分两个赋值。然后代码逻辑应该变得更清晰。

无论如何,由于只有在页面上不存在该类时才会出现问题,那应该是您的第一个测试:

function replaceRightClickIcefacesMethod() {
    if (jQuery.browser.msie) {
        var elem = jQuery(".singlePaneOfGlassBlock");

        if (elem.length > 0) {   // new test here!

            var oldName = elem.attr("oncontextmenu");
            var fn = String;

            if (typeof oldName == "function") {
                oldName = elem[0].getAttributeNode("oncontextmenu").value;
                fn = Function;
            }

            //do the replace
            oldName = oldName.replace('Ice.Menu.contextMenuPopup',
                                       'contextMenuPopupUpdated');

            //change oncontextmenu with the new value
            jQuery.each(elem, function() {
                this.setAttribute("oncontextmenu", fn(oldName));
            });
        }
    }
}

答案 1 :(得分:1)

更新:在问题中重新更新您的代码:

function replaceRightClickIcefacesMethod() {
    if (jQuery.browser.msie) {
        var elem = jQuery(".singlePaneOfGlassBlock"), oldName = elem
                .attr("oncontextmenu"), fn = String;

        if (typeof oldName == "function") {
            oldName = elem[0].getAttributeNode("oncontextmenu").value,
                    fn = Function;
        }

        // ====> This is where the bug is, you're assuming you have
        //       a string at this point, but you don't necessarily,
        //       because if there is no match at all, `attr` will
        //       return `undefined` or `null` (I forget which).
        //do the replace
        oldName = oldName.replace('Ice.Menu.contextMenuPopup',
                'contextMenuPopupUpdated');
        //change oncontextmenu with the new value
        jQuery.each(elem, function() {
            this.setAttribute("oncontextmenu", fn(oldName));
        })
    }
}

修复:

function replaceRightClickIcefacesMethod() {
    if (jQuery.browser.msie) {
        var elem = jQuery(".singlePaneOfGlassBlock"), oldName = elem
                .attr("oncontextmenu"), fn = String;

        if (typeof oldName == "function") {
            oldName = elem[0].getAttributeNode("oncontextmenu").value,
                    fn = Function;
        }

        // ====> Add this `if`:
        if (oldName) {
            //do the replace
            oldName = oldName.replace('Ice.Menu.contextMenuPopup',
                    'contextMenuPopupUpdated');
            //change oncontextmenu with the new value
            jQuery.each(elem, function() {
                this.setAttribute("oncontextmenu", fn(oldName));
            });
        }
    }
}

原始回答

在我看来,你错过了一些大括号(至少):

function replaceRightClickIcefacesMethod() {
if (jQuery.browser.msie) {
    var elem = jQuery(".singlePaneOfGlassBlock"), oldName = elem
            .attr("oncontextmenu"), fn = String;
    if (typeof oldName == "function") { // <=== Added { here
        oldName = elem[0].getAttributeNode("oncontextmenu").value,
                fn = Function;

        oldName = oldName.replace('Ice.Menu.contextMenuPopup',
                'contextMenuPopupUpdated');
        jQuery.each(elem, function() {
            this.setAttribute("oncontextmenu", fn(oldName));
        })
    } // <=== Added } here
}
}

以上是修正了缩进的内容:

function replaceRightClickIcefacesMethod() {
    if (jQuery.browser.msie) {
        var elem = jQuery(".singlePaneOfGlassBlock"), oldName = elem
                .attr("oncontextmenu"), fn = String;
        if (typeof oldName == "function") { // <=== Added { here
            oldName = elem[0].getAttributeNode("oncontextmenu").value,
                    fn = Function;

            oldName = oldName.replace('Ice.Menu.contextMenuPopup',
                    'contextMenuPopupUpdated');
            jQuery.each(elem, function() {
                this.setAttribute("oncontextmenu", fn(oldName));
            })
        } // <=== Added } here
    }
}

这是您的原始,并更正了缩进:

function replaceRightClickIcefacesMethod() {
    if (jQuery.browser.msie) {
        var elem = jQuery(".singlePaneOfGlassBlock"), oldName = elem
                .attr("oncontextmenu"), fn = String;
        if (typeof oldName == "function")
            oldName = elem[0].getAttributeNode("oncontextmenu").value,
                    fn = Function;

        // Note how these statements are NOT protected by the `if`
        // above, and so if `oldName` is `undefined` (as opposed to
        // being a String or Function.
        oldName = oldName.replace('Ice.Menu.contextMenuPopup',
                'contextMenuPopupUpdated');
        jQuery.each(elem, function() {
            this.setAttribute("oncontextmenu", fn(oldName));
        })
    }
}

或者可能是您错过了else条款,可能还有进一步的防御if

function replaceRightClickIcefacesMethod() {
    if (jQuery.browser.msie) {
        var elem = jQuery(".singlePaneOfGlassBlock"), oldName = elem
                .attr("oncontextmenu"), fn = String;
        if (typeof oldName == "function") {
            oldName = elem[0].getAttributeNode("oncontextmenu").value,
                    fn = Function;
        }
        else {    
            oldName = oldName.replace('Ice.Menu.contextMenuPopup',
                    'contextMenuPopupUpdated');
        }
        if (oldName) {
            jQuery.each(elem, function() {
                this.setAttribute("oncontextmenu", fn(oldName));
            });
        }
    }
}

但是很难说,我不能完全遵循逻辑。它的函数路径部分似乎没有任何改变,但字符串路径部分确实......

答案 2 :(得分:0)

而不是jQuery(oldName).length,为什么不执行oldName != null