【JS学习笔记】String

329 阅读7分钟

这是我参与更文挑战的第4天,活动详情查看: 更文挑战

String

获取单个字符

let str = "abcdef";
str.charAt(1) == str[1]   // true  "b"
str.charAt()		  // "a"   
str.charAt(6)             // ""

这里str虽然是原始类型的,但是依然可以像对象一样调用方法。在调用方法的时候,进行了三步操作。

  1. 创建一个String类型的实例;
  2. 调用实例上的特定方法;
  3. 销毁实例
let str = "abcdef";
str.length          // 6
str.length = 2;
str.length          // 6

不是对str本身操作的,是对新创建的实例操作的,但实例创建完就销毁了。

const obj = {
    toString() { return 1; }
}
let str = "abcdefg";
str[obj] == "b";   // true
let arr = [1,2,3,4];
str[obj] == 2;     // true

[]内会调用String()转型函数。

字符串不可变

字符串是原始类型的,所以自身是没有属性的,当原始值调用属性时,会发生自动包装机制,创建一个原始类型对应的包装类,调用完属性再销毁,一般用来读取属性值,而非修改,修改也没有意义。

let str = "abcd";
str.length;       		// 4
str.length = 3    
str.length;       		// 4
str.name = "alphabet";
str.name;                       // undefined
// ----------------------------------------
let strObj = new String("abcd");
strObj.length = 2;
strObj.length;          // 4

String对象中的length属性是不能改写的。也就是说,字符串是不可变的,一旦创建值就不能改变,要修改某个变量中的字符串值,必须先销毁原始的字符串,再把新的字符串保存到该变量上。

console.log(strObj);
// String {"abcd"}
// 0: "a"
// 1: "b"
// 2: "c"
// 3: "d"
// length: 4

String对象是原生类数组。只不过length属性不能改变。

String静态方法

String.fromCharCode()

输入一个或多个Unicode编码,返回对应的字符。

String.fromCharCode(65, 66, 67, 68);    // "ABCD"
String.fromCharCode(32) 		// " "      空格
String.fromCharCode(9)                  // "	"   制表符

String实例方法

在String.prototype上

charCodeAt()

返回字符串对应索引位置的字符的Unicode码。

let str = "abc";
str.codeCharAt(1);
// b的unicode码是98

concat()

连接两个字符串文本,并返回一个新的字符串。不影响原来的字符串。

let str = "123";
let s1 = "456";
let s2 = "789";
let s3 = "ABC";
let newStr = str.concat(s1,s2,s3);
// "123456789ABC"

拼接之前,会将参数转换成字符串形式。

不建议使用,强烈建议使用赋值操作符(+, +=)代替 concat 方法。

includes()

判断一个字符串是否包含另外一个字符串。区分大小写。

str.includes(searchString[, position])

searchString参数在判断之前会被转换成字符串。

position是可选参数,从当前字符串的哪个索引位置开始搜寻子字符串,默认值为 0。

endsWith()

确定一个字符串是否在另一个字符串的末尾。区分大小写。

String.prototype.endsWith = function(search, this_len) {
    // search 要搜索的字符串
    // this_len 被搜索的字符串的长度,可以控制哪个是末尾
    if (this_len === undefined || this_len > this.length) {
        this_len = this.length;
    }
    // 从末尾截取要搜索字符串的长度,然后和搜索字符串进行比较。返回布尔值。
    return this.substring(this_len - search.length, this_len) === search;
};
let str = "endsWith";
let b = str.endsWith("With"); // true

startsWith()

确定一个字符串是否在另一个字符串的开头。区分大小写。

if (!String.prototype.startsWith) {
    Object.defineProperty(String.prototype, 'startsWith', {
        value: function(search, pos) {
            // 这一串有点东西
            pos = !pos || pos < 0 ? 0 : +pos;
            // 从指定位置开始截取,截取给定字符串的长度。进行比较。
            return this.substring(pos, pos + search.length) === search;
        }
    });
}

indexOf()

返回调用它的String对象中第一次出现的指定值searchValue的索引,从 fromIndex 处进行搜索。如果未找到该值,则返回 -1。

str.indexOf(searchValue [, fromIndex])

详见MDN,太细了。

lastIndexOf()

返回调用String对象的指定值最后一次出现的索引,在一个字符串中的指定位置 fromIndex从后向前搜索。如果没找到这个特定值则返回-1 。

padEnd()

在当前字符串尾部填充指定的字符串, 直到达到指定的长度。 返回一个新的字符串。

if (!String.prototype.padEnd) {
    // targetLength 理想字符串的长度。
    // padString 替补字符串,不到理想状态,拿这个补齐。
    String.prototype.padEnd = function padEnd(targetLength,padString) {
        // 因为>>是运算符,会用Number进行转化。如果是NaN就会转换成0。
        // 也就是说,不是数字就转换成0,是数字就原值返回。
        targetLength = targetLength>>0;
        // 检查传入的padString参数,如果没传就返回 空格字符串,如果传了就转换成字符串。
        padString = String((typeof padString !== 'undefined' ? padString: " "));   // 空格字符串的长度为一
        // 如果this(当前字符串)已经是理想长度了,直接返回,不用处理。
        if (this.length > targetLength) {
            return String(this);
        }
        else {
            // 查看还缺几个字符。
            targetLength = targetLength - this.length;
            // 如果理想字符数量比替补字符串还要多的话,就重复替补字符串。
            if (targetLength > padString.length) {
                // 计算要重复的次数,并增加到替补字符串上。
                padString += padString.repeat(targetLength/padString.length); 
            }
            // 拼接字符串,根据之前算出来还缺几个字符,截取替补字符串。
            return String(this) + padString.slice(0,targetLength);
        }
    };
}
"1".padEnd(3);
// "1  "

不传第二参数时,默认是空格字符串。

padStart()

在当前字符串头部填充指定的字符串, 直到达到指定的长度。 返回一个新的字符串。

let hour = 9;
let min = 3;
let s = 45;
function format(time) {
    return String(time).padStart(2, "0");
}
let time = `${format(hour)}:${format(min)}:${format(s)}`
// 09:03:45

repeat()

指定某个字符串,重复多少次,返回一个新的字符串。

let str = "1";
str.repeat(4);
// "1111"	

重复后的字符串长度不超过,1 << 28 这么长,因为大部分浏览器不支持这么长。

slice()

提取字符串的某一部分,返回新字符串,不会改动原字符串。

str.slice(beginIndex[, endIndex])

beginIndex表示从哪个索引位置开始,endIndex表示在哪个索引位之前结束。

参数支持负数

如果参数是负数,会进行strLength + beginIndex的处理,strLength表示调用函数的字符串长度。

let str = "1234";
str.slice(1,3);
// "23"

从字符串索引1开始,到索引3之前结束。

其实就是,从索引1开始,截取(3 - 1)个字符。

str.slice(-2,-1);
// "3"

会转换成,str.slice((-2 + 4), (-1 + 4)),从倒数第二个开始,截取(-1 - -2)个字符。

str.slice(1,-1);
// "23"

从索引1开始到倒数第一个字符前结束。

str.slice(2);
// "34"
str.slice(2,100);
// "34"
str.slice(2,1);
// ""
str.slice(2,-100);
// ""

如果endIndex结束索引没有或者超出字符串长度,就从开始索引返回全部字符串。

如果是不服逻辑的索引,则返回空字符串。

str.slice(-100);
// "1234"
str.slice(-100, 2);
// "12"
str.slice(-100, -100);
// ""

beginIndex如果为负数,加上strLength还是为负数的话,就变为0处理。

str.slice(NaN);
// "1234"
str.slice(null);
// "1234"
str.slice(true);
// "234"
str.slice("abc");
// "1234"

传入的两个参数都会调用Number()进行转型,如果是NaN就当作0处理。

str.slice(0, 1.1);
// "1"
str.slice(0, "1.9");
// "1"

会先转换成数字类型,再转换成整型。向下取整。

substring()

和slice类似,提取字符串的某一部分,返回新字符串,不会改动原字符串。

str.substring(indexStart[, indexEnd])

参数不支持负数,负数会当作0处理。

注意事项

  • 如果 indexStart 等于 indexEndsubstring 返回一个空字符串。
  • 如果省略 indexEndsubstring 提取字符一直到字符串末尾。
  • 如果任一参数小于 0 或为NaN,则被当作 0
  • 如果任一参数大于 stringName.length,则被当作 stringName.length
  • 如果 indexStart 大于 indexEnd,则 substring 的执行效果就像两个参数调换了一样。见下面的例子。
let str = "abcdefg";

// 输出 "abc"
str.substring(0,3);
str.substring(3,0);
str.substring(3,-3);
str.substring(3,NaN);
str.substring(-2,3);
str.substring(NaN,3);

// 输出 "efg"
str.substring(4,7);
str.substring(7,4);

// 输出 ""
str.substring(4,4);

// 输出 "abcdef"
str.substring(0,6);

// 输出 "abcdefg"
str.substring(0,7);
str.substring(0,10);

先把小于0和为NaN的参数替换成0,再把大于字符串长度的参数替换成字符串长度,比较两参数,前一个参数大于后一个参数时就交换它们的位置。

substr()

与slice和substring略有不同,第二个参数表示截取的个数。不改变原字符串。

str.substr(start[, length])

start表示从哪个索引位置开始,length表示往后截取几个字符。

第一个参数支持负数

start为负数时,被看作strLength + start处理。

注意事项

  • 如果 start 为正值,且大于或等于字符串的长度,则 substr 返回一个空字符串。
  • 如果 start 为负值,则 substr 把它作为从字符串末尾开始的一个字符索引。
  • 如果 start 为负值且 abs(start) 大于字符串的长度,则当作0处理。
  • 如果 length 为 0 或负值,则 substr 返回一个空字符串。
  • 如果忽略 length,则 substr 提取字符,直到字符串末尾。
let str = "abcdefghij";

str.substr(1,2);   
// "bc"
str.substr(-3,2);  
// "hi"
str.substr(-3);  
// "hij"
str.substr(1);
// "bcdefghij"
str.substr(-20,2);
// "ab"
str.substr(20,2); 
// ""

toUpperCase()

返回一个全是大写形式的字符串。不改变原字符串。

当你将其上下文 this 值设置为非字符串类型,会将任何非字符串类型的值转为字符串。

const a = String.prototype.toUpperCase.call({
  toString: function toString() {
    return 'abcdef';
  }
});
// "ABCDEF"
const b = String.prototype.toUpperCase.call(true);
// "TRUE"

toLowerCase()

和toUpperCase相反,返回一个全是小写形式的字符串。

split()

把字符串按照指定的形式拆分成数组。

let str = "1,2,3,4,5,6";
let arr = str.split(",");
// [1, 2, 3, 4, 5, 6]
let str = "123456";
str.split("");
// [1,2,3,4,5,6]

直接拆分把字符串的每一位放入数组。

let str = "abcd";
str.split();
// ["acbd"]

不传参数,或参数不符合要求都会将其本身放入数组。

trim()

去掉字符串左右两端的空白字符。