为变更元素nodeValue分配变量new value

时间:2013-10-15 20:48:51

标签: javascript performance

以下代码运行正常,但我想让它更好:

function prodNameTrim(selector){
        var el = document.getElementsByClassName(selector);
        var len = el.length;
        for(i = 0; i<len; i++){
            aObj = el[i].getElementsByTagName('a');
            txtNode = aObj[0].childNodes[0].nodeValue;
            if(txtNode.length > 26){
                txtNode = txtNode.substring(0, 27) + ' ...';
            }
            aObj[0].childNodes[0].nodeValue = txtNode;
        }
    }

我不喜欢的是我首先在条件之前建立txtNode:

txtNode = aObj[0].childNodes[0].nodeValue;

在我通过条件处理变量以截断带有省略号的字符串后,我执行以下操作来替换DOM中的文本:

aObj[0].childNodes[0].nodeValue = txtNode;

我不得不相信有更好的方法可以做到这一点,但我不确定那是什么,我觉得我好像打破了DRY规则。

4 个答案:

答案 0 :(得分:2)

如果您只是想避免在任何地方重复aObj[0].childNodes[0]部分,可以使用txtNode变量来引用节点本身,而不是它的值:

function prodNameTrim(selector){
    var el = document.getElementsByClassName(selector);
    var len = el.length;
    var txtNode;  // declare txtNode with var
    for(var i = 0; i<len; i++){
        txtNode = el[i].getElementsByTagName('a')[0].childNodes[0];
        if(txtNode.nodeValue.length > 26){
            txtNode.nodeValue = txtNode.nodeValue.substring(0, 27) + ' ...';
        }
    }
}

你会发现你到处都在重复txtNode.nodeValue,但最好还是每次都要包含aObj[0].childNodes[0]。并且不需要在if语句之后将子字符串版本写回节点的行,因为该更新现在直接在if内发生。

另请注意,您应该使用var声明所有变量,否则它们将成为全局变量。 (我上面显示的方式实际上根本不需要aObj变量。)

答案 1 :(得分:2)

我会建议:

function prodNameTrim(selector){
    var el = document.getElementsByClassName(selector),
        len = el.length, node;
    for(var i = 0; i < len; i++) {
        node = el[i].getElementsByTagName('a')[0].firstChild;
        if(node.nodeValue.length > 26){
            node.nodeValue = node.nodeValue.substring(0, 27) + ' ...';
        }
    }
}

的变化:

  1. 声明所有局部变量(因此没有隐式全局变量 - 您没有声明iaObjtxtNode
  2. 在不需要的情况下跳过aObj中间件
  3. 避免使用textNode,因为它不需要
  4. 直接分配给nodeValue
  5. 仅在if语句中对nodeValue进行赋值,因为这是唯一更改的位置
  6. 使用.firstChild代替.childNodes[0]

  7. 我想知道这是否可行(可能需要IE9或更高版本,并且希望确定HTML以确定并运行一些浏览器测试),但一般的想法是使用querySelectorAll()并结合两个搜索进入一个更复杂的CSS选择器:

    function prodNameTrim(rootClass) {
        var items = document.querySelectorAll("." + rootClass + " a:first-of-type"), node;
        for (var i = 0; i < items.length; i++) {
            node = items[i].firstChild;
            if (node.nodeValue.length > 26) {
                node.nodeValue = node.nodeValue.substring(0, 27) + ' ...';
            }
        }
    }
    

    注意,第二个实现假定prodNameTrim()的参数是一个类名(就像OP的版本一样)。


    或者,如果每个选择器父级中只有一个链接标记,那么您可以简单地使用它,它应该适用于所有现代浏览器:

    function prodNameTrim(rootClass) {
        var items = document.querySelectorAll("." + rootClass + " a"), node;
        for (var i = 0; i < items.length; i++) {
            node = items[i].firstChild;
            if (node.nodeValue.length > 26) {
                node.nodeValue = node.nodeValue.substring(0, 27) + ' ...';
            }
        }
    }
    

答案 2 :(得分:1)

如果你想在一行中进行条件截断,你可以这样做:

function prodNameTrim(selector){
    var el = document.getElementsByClassName(selector),
        len = el.length, node;
    for(var i = 0; i < len; i++) {
        node = el[i].getElementsByTagName('a')[0].firstChild;
        node.nodeValue.substring(0, 27) + (node.nodeValue.length > 26 ? ' ...', '')
    }
}

答案 3 :(得分:0)

你正在以正确的方式去做 - 除了你引入了一个不必要的全局变量。第一项任务应该是:

var txtNode = aObj[0].childNodes[0].nodeValue;

使用var声明!您还可以在函数顶部的for循环之前声明变量。如nnnnnn所述,您还要为iaObj创建非预期的全局变量。所以你可以通过在for循环之前插入这个问题来解决所有这三个问题:

var i, aObj, txtNode;