一个递归函数的漏洞及优化

现在有一个需求:

如果“一个字符串”超出“容器宽度”,将字符串截断最后一个字符、并在末尾加上‘...’ ,再次判断是否需要截断。直至字符串小于容器宽度。

下面SliceLabelStr函数采用了递归:
如果文字超出宽度,在attrStyle函数中将原字符截断末尾字符并加上‘...’ 再次调用sliceLabelStr判断是否超出宽度。
直至获得宽度合适的字符串并输出。

需要优化的递归函数
sliceLabelStr = function( textWidth, textStr) {
    var str;
   
    if(超出宽度) {
        dataLabel2 = attrStyle(textStr);
        var newTextWidth =  dataLabel2.text && dataLabel2.text.element.getBoundingClientRect().width;
        var textStr = dataLabel2.text.textStr;
        sliceLabelStr( newTextWidth, textStr);
    } else {
        str = attrStyle(textStr, true);
        return str; 
    }  
}

这样看起来没问题。其实需要优化很多地方。

1、递归没有出口

  1. 这个递归函数被调用了10遍,在11遍的时候符合了出口条件退出了,
    那么在第10遍没退出的时候,1到10次的函数都没有退出,只有在第11遍符合了出口条件return了以后,就会从11~1倒着依次退出

附上一张太阳神手写的解释图
图片描述

优化方法1
if(textWidth > containerWidth) {
        dataLabel2 = attrStyle(textStr);
        var newTextWidth =  dataLabel2.text && dataLabel2.text.element.getBoundingClientRect().width;
        var textStr = dataLabel2.text.textStr;
        return sliceLabelStr( newTextWidth, textStr);//有返回值
    } 

1、上述原因是递归没有出口,而且if语句中调用本函数递归的时候没有返回值。

2、有时会产生“调用栈溢出”的情况。

2、在if判断条件中,由于在某种情况下textWidth没有变化造成了无限递归

3、用do...while 代替 递归

sliceLabelStr = function(forX2Array, textWidth, textStr) {
    var str,
        sliceStr = textStr.text && textStr.text.textStr || textStr;

    if(compareTextLength(forX2Array, textWidth)) {
        var n=0;

        do{
            n++;
        }
        while(sliceStr.substr(0,n)!=sliceStr && attrLabel2Style(forX2Array[0], sliceStr.substr(0,n)).getBBox()["width"]<ContainerWidth(forX2Array))

        return sliceStr.substr(0,n);

    } else {
        str = attrLabel2Style(forX2Array[0], sliceStr, true);
        return str;
    }
}

逻辑比较直观,简单能用循环的就用循环,递归一般用在复杂算法,比如弗洛伊德,A+之类

4、这是SVGElement,如果是普通的DOM元素。可以用如下方法。

图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值