欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义实现JavaScript的String方法

程序员文章站 2022-04-04 08:04:46
...

自定义实现JavaScript的String方法

length方法


function String(str) {
    this.str = str;
    this.length = 0;

    var i=0;
    while(str[i]) {
        i++;
    }
    this.length = i;
}

var str = new String('abc');
console.log(str); // str.length

charAt

  • 返回指定位置的字符,参数是从0开始编号的位置。
String.prototype.charAt = function(index) {
    return this.length <=index? "": this.str[index];
}

// console.log( str.charAt(9) );// -1

concat

  • 方法用于连接两个字符串,返回一个新字符串,不改变原字符串。
 /**
 * concat方法用于连接两个字符串,返回一个新字符串,不改变原字符串。
*/
String.prototype.concat = function() {
    // 累计当前string的字符串
    let st =Object.keys(this).filter(index => index != 'length').reduce((total, index)=>{
        return total += this[index];
    }, "")
    // 参数字符串的值 也进行累加
    for(let i=0; i<arguments.length; i++) {
        st += arguments[i];
    }

    return st;
}

// console.log(str.concat('this', 'is')); // abcthisis

自定义方法

 /***
* 返回整个字符串
**/
String.prototype.return_all = function() {
    let st = "";
    Object.keys(this).forEach((item, index)=> {
        if(index !== this.length) {
            st += this[index];
        }
    })
    return st;
}

/***
* 返回开始和结束的字符串
**/
String.prototype.return_sub = function(start, end) {
    let st = "";
    
    Object.keys(this).forEach((item, index)=> {
        if(index !== this.length && index >=start && index < end) {
            st += this[index];
        }
    })
    return st;
}

slice

  • 用于从原字符串取出子字符串并返回,不改变原字符串。
  • 它的第一个参数是子字符串的开始位置,第二个参数是子字符串的结束位置(不含该位置)。
String.prototype.slice = function() {
    let start = 0;
    let end = 0;

    // 返回全部长度
    if(arguments.length ===1 && arguments[0] === 0  || (arguments.length === 0)) {
        let st = "";
        Object.keys(this).forEach((item, index)=> {
            if(index !== this.length) {
                st += this[index];
            }
        })
        return st;
    }

    // 第一个参数的处理
    if(arguments.length === 1) {
        if(arguments[0] > 0){// "sfdsfdsf".slice(3)
            start = arguments[0];
            end = this.length;
        }else { // 'JavaScript'.slice(-6) // "Script" 小于0的时候 需要字符串的长度,因为为负数,是从后往前计算的
            start = arguments[0] + this.length;
            end = this.length;
        }
    }else if(arguments.length === 2) { // 两个参数的处理, 负数的时候 代表从后向前取出
        start = arguments[0]>=0 ? arguments[0] : arguments[0] + this.length;
        end = arguments[1]>=0 ? arguments[1] : arguments[1] + this.length;
    }

        // 第一个参数大于第二个参数 返回""
    if(start > end) {
        return "";
    }
        
    return this.return_sub(start, end);
}

console.log( str.slice(0, 4) );// Java
console.log(str.slice(4)); // Script
console.log(str.slice(-6)); // Script
console.log(str.slice(0, -6)); // Java
console.log(str.slice(-2, -1)); // p
console.log(str.slice(2, 1)); // ""

substring

  • substring方法用于从原字符串取出子字符串并返回,不改变原字符串,跟slice方法很相像。
  • 它的第一个参数表示子字符串的开始位置,第二个位置表示结束位置(返回结果不含该位置)。
String.prototype.substring = function() {
        
    let start = 0;
    let end = 0;

    if(arguments.length === 0) {
        end = this.length;
    }else if(arguments.length === 1) {
        if(arguments[0]>0) {
            start = arguments[0];
            end = this.length;
        }else {  // 如果参数是负数,substring方法会自动将负数转为0。
            start = 0; // 这里
            end = this.length;
        }
    }else if(arguments.length === 2){
        start = arguments[0]>=0? arguments[0]: 0;
        end = arguments[1]>=0? arguments[1]: 0;
        if(start > end) {
            let t ;
            t = start;
            start = end;
            end = t;
        }
    }

    return this.slice(start, end);
}

console.log( str.substring(0, 4) ); // Java
console.log( str.substring(4) ); // Script
console.log( str.substring(10, 4)  ); // Script
console.log( str.substring(4, 10)  ); // Script
console.log( str.substring(-3)  ); // Script
console.log( str.substring(4, -3)  ); // Script

substr

  • substr方法用于从原字符串取出子字符串并返回,不改变原字符串,跟slice和substring方法的作用相同。
  • substr方法的第一个参数是子字符串的开始位置(从0开始计算),第二个参数是子字符串的长度。
  • 如果第一个参数是负数,表示倒数计算的字符位置。如果第二个参数是负数,将被自动转为0
String.prototype.substr = function() {
    let start = 0;
    let end = 0;

    if(arguments.length === 0) {
    return this.return_all();
    }else if(arguments.length === 1) {
    if(arguments[0]>0) {
        start = arguments[0];
        end = this.length;
    }else {
        start = arguments[0] + this.length;
        end = this.length;
    }
    }else if(arguments.length === 2) {
    start = arguments[0]>0?arguments[0]: arguments[0] + this.length;
    end = arguments[1]>0? start + arguments[1] : 0;
    }

    return this.slice(start, end);
}

console.log(str.substr(4, 6)); // "Script"
console.log(str.substr(4)); // "Script"
console.log(str.substr(-6)); // "Script"
console.log(str.substr(4, -1)); // "" 参数-1自动转为0,表示子字符串长度为0,所以返回空字符串。

indexOf

  • 用于确定一个字符串在另一个字符串中第一次出现的位置,返回结果是匹配开始的位置。如果返回-1,就表示不匹配。
// 封装的kmp算法
function kmp(target, pattern) {
    function prefix_table(pattren, prefix, n) {
        prefix[0] = 0;
        let len = 0;
        let i = 1;
        while (i < n) {
            if(pattren[i] == pattren[len]) {// 寻找前后最长子串
                len++;
                prefix[i] = len;
                i++;
            }else {
                if(len > 0) { // 如果不相等的话,则最退到当前前缀表达式的前面一位对应的值
                len = prefix[len-1];
                }else { // 如果在最前面 需要匹配为0
                    prefix[i] = len;
                    i++;
                }
            }
        }
    }   

    // 让前缀表第一个变为-1
    function move_prefix_table(prefix, n){
        let i=0;
        for(i=n-1;i>0;i--) {
            prefix[i] = prefix[i-1];
        }
        prefix[0] = -1;
    }
    /**
     * target 代表原始的字符串
     * pattern 代表需要匹配的子串
     * 
     * pattern AB
     * targer BAABABABS
     * return 2
     * */
    return function () {
        let n = pattern.length;
        let m = target.length;
        //初始化为0
        const prefix = new Array(m).fill(0);
        
        prefix_table(pattern, prefix, n);
        move_prefix_table(prefix, n);
        
        // target[i] len(targer) = m;
        // pattern[j] len(pattern) = n;
        let i=0;
        let j=0;
        while(i < m) {
            if(j == n-1 && target[i] == pattern[j]) {
                // console.log(i-j)
                // j = prefix[j];
                return i-j;
            }
            if(target[i] == pattern[j]) { // 当匹配的串 与模式串相等时
                i++;
                j++;
            }else {
                j = prefix[j]; // 不相等时, prefix需要退回到前一个最大的值
                if(j==-1) { // 开头的时候
                    i++;
                    j++;
                }
            }
        }


        return -1;
    }
}



String.prototype.indexOf = function() {
    let start = 0;
    let end = 0;

    if(arguments.length === 1) {
        const pattern = arguments[0];
        const target = this.return_all(); 
        return kmp(target, pattern)();
    }else if(arguments.length == 2) {
        let start = arguments[1];
        let end = this.length;
        let st = this.return_sub(start, end);
        // console.log(st);
            
        const index = kmp(st, arguments[0])();
        if(index < 0) {
            return -1;
        }else {
            return index + start;
        }
    }
}


console.log( str.indexOf('Java') ); // 0
console.log( str.indexOf('Sc') ); // 4
console.log( str.indexOf('script') ); // -1
console.log( str.indexOf('i', 6) ); // 7

lastIndexOf

  • 可以使用逆序的字符串 在套用kmp

trim

  • trim方法用于去除字符串两端的空格,返回一个新字符串,不改变原字符串。
  • 方法去除的不仅是空格,还包括制表符(\t、\v)、换行符(\n)和回车符(\r)。
String.prototype.trim = function() {
    let start = 0;
    let end = this.length-1;
    let arr = [' ', '\t', '\v', '\n', '\r']
    
    while(arr.indexOf(this[start]) != -1) {
        start++;
        // console.log('111')
    }

    while(arr.indexOf(this[end]) != -1) {
        end--;
    }
    end++;

    return this.return_sub(start, end);
}

var str1 = new String('           JavaScript            \t');
var str1 = new String('\r\nabc \t');
console.log(str1.trim())