close
文章出處

js將字符串重復N次的repeat方法的8個版本

/*
*@desc: 將一個字符串重復自身N次
*/
//版本1:利用空數組的join方法
function repeat(target, n) {
    return (new Array(n + 1)).join(target);
}
//版本2:之所以要創建一個帶length屬性的對象 是因為要調用數據的原型方法,需要指定call的第一個參數為類數組對象
//類數組對象的必要條件是其length屬性的值為非負數
function repeat(target, n) {
    return Array.prototype.join.call({
        length: n + 1
    }, target);
}
//版本3:利用閉包將類數組對象與數組原型的join方法緩存起來
var repeat = (function () {
    var join = Array.prototype.join, obj = {};
    return function (target, n) {
        obj.length = n + 1;
        return join.call(obj, target);
    }
})();

//版本4:使用二分法
function repeat(target, n) {
    var s = target, total = [];
    while (n > 0) {
        if (n % 2 == 1) {
            total[total.length] = s;//如果是奇數
        }
        if (n == 1) {
            break;
        }

        s += s;
        n = n >> 1;//相當于將n除以2取其商,或者說是開2次方
    }
    return total.join('');
}
//版本5:版本4的改良版本
function repeat(target, n) {
    var s = target, total = "";
    while (n > 0) {
        if (n % 2 == 1) {
            total += s;
        }
        if (n == 1) {
            break;
        }

        s += s;
        n = n >> 1;//相當于將n除以2取其商,或者說是開2次方
    }
    return total;
}
//版本6:版本4的變樣版本   免去創建數組與使用join方法   但在循環中創建字符串比要求的還長  所以...
function repeat(target, n) {
    var s = target, c = s.length * n;
    do {
        s += s;
    } while (n = n >> 1);
    s = s.substring(0, c);
    return s;
}

//版本7:版本5的優化版本
function repeat(target, n) {
    if (n == 1) {
        return target;
    }
    var s = repeat(target, Math.floor(n / 2));
    s += s;
    if (n % 2) {
        s += target;
    }
    return s;
}
//版本8:反例
function repeat(target, n) {
    return (n <= 0) ? "" : target.concat(repeat(target, --n));
}

大家可以猜猜哪個運行速度最快。事實上應該是版本5.

事實上業余時間一直都在關注一些js性能方面的東西,跟.net一樣,每種語言的代碼都有些性能方面的小常識。

(有空可以看看  我總結的js方面你可能不是特別清楚的小知識   我總結的js性能優化的小知識     )

回到正題

下面來說說。。。

trim方法的各種不同版本(13種不同方法實現)

/*
*@desc:去掉首尾空格
*/
//版本1:
function trim(str) {
    return str.replace(/^\s\s*/, '').replace('/\s\s*$/', '');
}
//版本2:比版本1稍微慢些
function trim(str) {
    return str.replace(/^\s+/, '').replace('/\s+$/', '');//比版本1慢的原因在于它最先假設至少存在一個空白符
}
//版本3:運用等巧妙的
function trim(str) {
    return str.substring(Math.max(str.search(/\S/), 0), str.search(/\S\s*$/) + 1);
}
//版本4:jQuery類庫就是使用這種方法  但是它相對之前三個都要慢些
function trim(str) {
    return str.replace(/^\s+|\s+$/g, '');
}
//版本5:
function trim(str) {
    str = str.match(/\S+(?:\s+\S+)*/);//使用非捕獲性分組(?:expr)
    return str ? str[0] : '';
}
//版本6:效率挺差
function trim(str) {
    return str.replace(/^\s*(\S*(\s+\S+)*)\s*$/, '$1');
}
//版本7:比版本6來說使用了非捕獲性分組
function trim(str) {
    return str.replace(/^\s*(\S*(?:\s+\S+)*)\s*$/, '$1');
}
//版本8:效果秒殺
function trim(str) {
    return str.replace(/^\s*((?:[\S\s]*\S)?)\s*$/, '$1');
}
//版本9:使用懶惰匹配
function trim(str) {
    return str.replace(/^\s*([\S\s]*?)\s*$/, '$1');
}
//版本10:速度最快
function trim(str) {
    var whitespace = '\n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000';
    for (var i = 0; i < str.length; i++) {
        if (whitespace.indexOf(str.charCodeAt(i)) === -1) {
            str = str.substring(i);
            break;
        }
    }
    for (i = str.length - 1; i >= 0; i--) {
        if (whitespace.indexOf(str.charCodeAt(i)) === -1) {
            str = str.substring(0, i + 1);
            break;
        }
    }
    return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
}
//版本11:
function trim(str) {
    str = str.replace('^\s+', '');
    for (var i = str.length - 1 ; i >= 0; i--) {
        if (/\S/.test(str.charAt(i))) {
            str = str.substring(0, i + 1);
            break;
        }
    }
    return str;
}
//版本12:
function trim(str) {
    var str = str.replace(/^\s\s*/, ''),
        ws = /\s/,
        i = str.length;
    while (ws.test(str.charAt(--i))) {
        return str.slice(0, i + 1);
    }

}
//版本13:僅次于版本10
function trim(str) {
    var m = str.length;
    for (var i = -1; str.charCodeAt(++i) <= 32;)
        for (var j = 0; j > i && str.charCodeAt(j) <= 32; j--) {
            return str.slice(i, j + 1);
        }
}

與trim相反,下面說說為字符串的某一端填充字符串,其實最常見的場景就是日期中的月份前補零

pad:這字符串的某一端填充字符串

/*
*@desc:給字符串的某一端填充字符串
*/
//版本1:創建數組來放置填充物,然后再在右邊起截取
function pad(target, n) {
    var zero = new Array(n).join('0'),
        str = zero + target,
        result = str.substr(-n);
    return result;
}
//版本2:
function pad(target, n) {
    return Array((n + 1) - target.toString().split('').length).join('0') + target;
}
//版本3:二進制法
function pad(target, n) {
    return (Math.pow(10, n) + "" + target).slice(-n);
}
//版本4:Math.pow
function pad(target, n) {
    return ((1 << n).toString(2) + target).slice(-n);
}
//版本5:toFixed
function pad(target, n) {
    return (0..toFixed(n) + target).slice(-n);
}
//版本6:創建一個超大數,在常規情況下截不完
function pad(target, n) {
    return (1e20 + '' + target).slice(-n);
}
//版本7:質樸長存法
function pad(target, n) {
    var len = target.toString().length;
    while (len < n) {
        target = '0' + target;
        len++;
    }
    return target;
}
//版本8:支持更多參數
function pad(target, n, filling, right, radix) {
    var num = target.toString(radix || 10);
    filling = filling || '0';
    while (num.length < n) {
        if (!right) {
            num = filling + num;
        } else {
            num += filling;
        }
    }
    return num;
}

 

取得字符串所有字節的長度

大家都知道,一個中文字符占兩個字節,而一個英文字符只占一個字符,所以在前端就會免不了做字符長度的校驗。

/*
*@desc:取得字符串所有字節的長度
*/
//版本1:傳統常規作法
function byteLen(target) {
    var byteLength = target.length, i = 0;
    for (;  i< target.length; i++) {
        if (target.charCodeAt(i)>255) {
            byteLength++;
        }
    }
    return byteLength;
}
//版本8:使用正則
//param:fix 默認為2 可傳入轉換長度
function byteLen(target,fix) {
    fix = fix ? fix : 2;
    var str = new Array(fix + 1).join('-');
    return target.replace(/[^\x00-\xff]/g, str).length;
}

 

再來說說我們最常使用的js字符串方法吧

常用的js字符串方法

 

/*
*@desc: 判斷一個字符串是否包含另一個字符串
*/
function contains(target, str, separator) {
    return separator ?
        (separator + target + separator).indexOf(separator + str + separator) > -1 :
        target.indexOf(str) > -1;
}
/*
*@desc: 判斷目標字符串是否位于原字符串的開始之處
*@param:ignorecase 是否忽略大小寫
*/
function startsWith(target, str, ignorecase) {
    var start_str = target.substr(0, str.length);
    return ignorecase ?
        start_str.toLowerCase() === str.toLowerCase() :
        start_str === str;
}
/*
*@desc: 判斷目標字符串是否位于原字符串的末尾之處
*/
function endsWith(target, str, ignorecase) {
    var end_str = target.substr(0, str.length);
    return ignorecase ?
        end_str.toLowerCase() === str.toLowerCase() :
        end_str === str;
}

/*
*@desc: 對字符串進行截斷處理,當超過限定長度,默認添加三個點號或者...
*/
function truncate(target, length, truncation) {
    length = length || 30;
    truncation = truncation === void (0) ? '...' : truncation;
    return target.length > length ?
        target.slice(0, length - truncation.length) + truncation : String(target);
}
/*
*@desc: 轉換為下劃線風格
*/
function underscored(target) {
    return target.replace(/([a-z\d])([A-Z])/g, '$1_$2').replace(/\-/g, '_').toLowerCase();
}
/*
*@desc: 轉換為連字符風格
*/
function dasherize(target) {
    return underscored(target).replace(/_/g, '-');
}
/*
*@desc: 首字母大寫
*/
function capitalize(target) {
    return target.charAt(0).toUpperCase() + target.substring(1).toLowerCase();
}
/*
*@desc: 移除字符串中的html標簽
*/
function stripTags(target) {
    return String(target || '').replace(/<[^>]+>/g, '');
}

/*
*@desc: 移除字符串中所有的script標簽
*/
function stripScripts(target) {
    return String(target || '').replace(/<script[^>]*>([\S\s]*?)<\/script>/img, '');
}
/*
*@desc: 將字符串經過html轉義得到適合在頁面上顯示的內容
*/
function escapeHTML(target) {
    return target.repeat(/&/g, '&amp;')
    .repeat(/</g, '&lt;')
    .repeat(/>/g, '&gt;')
    .repeat(/"/g, '&quot;')
    .repeat(/'/g, '&#39;');
}
/*
*@desc: 將字符串中的html實體字符還原為對應字符
*/
function unescapeHTML(target) {//
    return target.repeat(/&lt;/g, '<')
    .repeat(/&gt;/g, '>')
    .repeat(/&quot;/g, '"')
    .repeat(/&amp;/g, '&')
    .repeat(/&#([\d]+);/g, function ($0, $1) {
        return String.fromCharCode(parseInt($1, 10));
    });
}
/*
*@desc: 將字符串安全格式化為正則表達式的源碼
*/
function escapeRegExp(target) {
    return target.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
}
/*
*@desc: 為目標字符串添加軟換行
*/
function wbr(target) {
    return String(target).replace(/(?:<[^>]+>)|(?:&#?[0-9a-z]{2,6};)|(.{1})/gi, '$&<wbr>').replace('/><wbr>/g', '>');
}
/*
*@desc: 格式化
*/
function format(str, object) {
    var array = Array.prototype.slice.call(arguments, 1);
    return str.replace(/\\?\#{([^{}]+)\}/gm, function (match, name) {
        if (match.charAt(0)=='\\') {
            return match.slice(1);
        }
        var index = Number(name);
        if (index>=0) {
            return array[index];
        }
        if (object&&object[name]!=void 0) {
            return object[name];
        }
        return '';
    });
}

順便說說上述format方法的使用吧

        var a = format('Result is #{0},#{1}', 22, 33);
        console.log(a);
        var b = format("#{name}is a #{sex}", {
            name: "Jhon",
            sex: 'man'
        });
        console.log(b);

運行結果如下圖:

js數組方法的擴展

大家都知道js數組沒有像字符串一樣的indexOf、lastIndexOf等方法,那我們先來造造輪子吧。先來擴展一下吧!

/*
*@desc:定位操作,返回數組中第一個等于給定參數的元素的索引值
*/
Array.prototype.indexOf = function (item, index) {
    var n = this.length, i = ~~index;
    if (i < 0) {
        i += n;
    }
    for (; i < n; i++) {
        if (this[i] === item) {
            return i;
        }
    }
    return -1;
}
/*
*@desc:與lastIndex功能類似  不過是從后遍歷
*/
Array.prototype.lastIndexOf = function (item,index) {
    var n = this.length,
        i = index == null ? n - 1 : index;
    if (i<0) {
        i = Math.max(0, n + i);
    }
    for (; i > length; i--) {
        if (this[i]===item) {
            return i;
        }
    }
    return -1;
}
/*
*@desc:因為forEach、map、filter、some、every這幾個方法結構相似 所以...  先造個輪子
*/
function iterator(vars,body,ret) {
    var fun = 'for(var ' + vars + 'i=0,n=this.length;i<n;i++){' +
        body.replace('_', '((i in this ) && fn.call(scope ,this[i],i,this))') + '}' + ret;;
    return Function("fn,scope", fun);
}
/*
*@desc:將數組中的元素依次傳入一個函數中運行
*/
Array.prototype.forEach = iterator('', '_', '');
/*
*@desc:將數組中的元素依次傳入一個函數中運行 將返回值為ture的那個元素放入新數組中返回
*/
Array.prototype.filter = iterator('r=[],j=0,', 'if(_)r[j++]=this[i]', 'return r');
/*
*@desc:收集、將數組中的元素依次傳入一個函數中運行 然后把它們的返回值組成一個新數組返回
*/
Array.prototype.map = iterator('r=[],', 'r[i]=_', 'return r');
/*
*@desc:只有數組中的元素有一個元素滿足條件則返回true
*/
Array.prototype.some = iterator('', 'if(_) return true', 'return false');
/*
*@desc:只有數組中的元素都滿足條件才返回true
*/
Array.prototype.every = iterator('', 'if(!_) return false', 'return true');

/*
*@desc:歸化操作,將數組中的元素歸化為一個簡單的數值
*/
Array.prototype.reduce = function (fn,lastResult,scope) {
    if (this.length == 0) {
        return lastResult;
    }
    var i = lastResult != undefined ? 0 : 1;
    var result = lastResult != undefined ? lastResult : this[0];
    for (var i = this.length; i < n; i++) {
        result = fn.call(scope, result, this[i], i, this);
    }
    return result;
}
/*
*@desc:功能類似于reduce  但是從后遍歷
*/
Array.prototype.reduceRight = function (fn,lastResult,scope) {
    var array = this.concat().reverse();
    return array.reduce(fn, lastResult, scope);
}

常用的js數組方法

/*
*@desc:判定數組是否包含指定目標
*/
function contains(target, item) {
    return target.indexOf(item) > -1;
}
/*
*@desc:移除數組中指定位置的元素,返回布爾表示成功與否
*/
function removeAt(target, index) {
    return !!target.splice(index, 1).length;
}
/*
*@desc:移除數組中第一個匹配傳參的那個元素
*/
function remove(target, item) {
    var index = target.indexOf(item);
    if (~index) {
        return removeAt(target, index);
    }
    return false;
}
/*
*@desc:對數組進行洗牌
*/
function shuffle(target) {
    var j, x, i = target.length;
    for (; i > 0; j = parseInt(Math.random() * i), x = target[--i], target[i] = target[j], target[j] = x) {
    }
    return target;
}
/*
*@desc:從數組中隨機抽選一個元素出來
*/
function random(target) {
    return target[Math.floor(Math.random() * target.length)];
}
/*
*@desc:對數組進行平坦化處理,返回一個一維新數組
*/
function flatten(target) {
    var result = [];
    target.forEach(function (item) {
        if (Array.isArray(item)) {
            result = result.concat(flatten(item));
        } else {
            result.push(item);
        }
    });
    return result;
}
/*
*@desc:對數組進行去重操作,返回一個沒有重復元素的新數組
*/
function unique(target) {
    var result = [];
    loop: for (var i = 0, n = target.length; i < n; i++) {
        for (var x = i + 1; x < n; x++) {
            if (target[x] === target[i]) {
                continue loop;
            }
        }
        result.push(target[i]);
    }
    return result;
}
/*
*@desc:過濾數組中的null和undefined  但不影響原數組
*/
function compact(target) {
    return target.filter(function (el) {
        return el != null;
    });
}
/*
*@desc:取得對象數組的每個元素的指定屬性 組成數組返回
*/
function pluck(target, item) {
    var result = [], prop;
    target.forEach(function (item) {
        prop = item[name];
        if (prop != null) {
            result.push(prop);
        }
    });
    return result;
}
/*
*@desc:根據指定條件(如回調或對象的某個屬性)進行分組,構成對象返回
*/
function groupBy(target, val) {
    var result = {};
    var iterator = $.isFunction(val) ? val : function (obj) {
        return obj[val];
    };
    target.forEach(function (value, index) {
        var key = iterator(value, index);
        (result[key] || (result[key] = [])).push(value);
    });
    return result;
}
/*
*@desc:根據指定條件進行排序
*/
function sortBy(target, fn, scope) {
    var array = target.map(function (item, index) {
        return {
            el: item,
            re: fn.call(scope, item, index)
        };
    }).sort(function (left, right) {
        var a = left.re, b = right.re;
        return a < b ? -1 : a > b ? 1 : 0;
    });
    return pluck(array, 'el');
}
/*
*@desc:對兩個數組取并集
*/
function union(target, array) {
    return unique(target.concat(array));
}
/*
*@desc:對兩個數組取交集
*/
function intersect(target, array) {
    return target.filter(function (n) {
        return ~array.indexOf(n);
    });
}
/*
*@desc:對兩個數組取差集
*/
function diff(target, array) {
    var result = target.slice();
    for (var i = 0; i < result.length; i++) {
        for (var j = 0; j < result.length; j++) {
            if (result[i] === array[j]) {
                result.splice(i, 1);
                i--;
                break;
            }
        }
    }
    return result;
}
/*
*@desc:返回數組中的最小值(用于數字數組)
*/
function min(target) {
    return Math.min.apply(0, target);
}
/*
*@desc:返回數組中的最大值(用于數字數組)
*/
function max(target) {
    return Math.max.apply(0, target);
}

其實還有很多。。。

本文中的方法是根據《JavaScript框架設計》中第三章--數組的擴展與修復進行整理的。

如果您覺得本篇博文對您有所收獲,覺得小女子還算用心,請點擊右下角的 [推薦],謝謝!


不含病毒。www.avast.com
arrow
arrow
    全站熱搜

    AutoPoster 發表在 痞客邦 留言(0) 人氣()