自定义实现JavaScript的String方法

自定义实现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())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值