Web前端:JavaScript基础篇之字符串的引用类型String

首先大家需要知道是,原始值(基本数据类型)string和String对象之间的关系:

String是原始值string的原始值包装类型的对象 

例:

        let s1 = 'some text';

        let s2 = s1.substring(2);

以上例子s1是一个包含字符串的变量,它是一个原始值!第二行紧接着在s1上调用了substring()方法并把结果保存在s2中。我们要知道,原始值本身不是对象,因此逻辑上不应该有方法。而实际上这个例子又确实按预期运行了。这是因为后台做了以下操作!

        1、创建一个String类型的实例;

        2、调用实例上的特定方法;

        3、销毁实例;

        想象为后台操作:

        let s1 = new String('some text');

        let s2 = s1.substring(2);

        s1 = null;

这种行为可以让原始值拥有对象的行为。对布尔值和数值而言,以上三步也会在后台发生,只不过使用的是Boolean和Number包装类型而已!

引用类型和原始值包装类型的主要区别在于对象的生命周期。在通过new关键字实例化引用类型后,得到的实例会在离开作用域时被销毁。而自动创建的原始值包装对象则只存在于访问它的那行代码执行期间。这意味着在运行时,不能给原始值添加属性或方法!

例:

        let s1 = 'some text';

        s1.age = 15;

        console.log(s1.age);//undefined

这里第二行代码尝试给第一行代码添加一个属性age,可是第三行代码访问age时,它却不存在了。原因就是第二行代码在运行时会临时创建一个String对象,而当第三行代码执行时,这个对象已经被销毁了。实际上,第三行代码在这里创建了自己的对象,但这个对象没有age这个属性!

由上可见String对象的方法可以在所有字符串原始值上调用。有三个继承的方法valueOf()、toLocaleString()和toString()都返回对象的原始字符串值!

每个String对象都有一个length属性,表示字符串中字符的数量。来看看下面的例子:

        let str = 'hello world';

        console.log(str.length);//'11'

这个例子输出了字符串中包含的字符数量:11。

注:即使字符串中包含双字节字符(而不是单字节的ASCII字符),也仍然会按单字符来计数。

JavaScript字符

JavaScript字符串由16位码元(code unti)组成。对多数字符串来说,每16位码元对应一个字符。换句话说,字符串length属性表示字符串包含多少16位码元:

let message = 'abcde';

console.log(message.length);//5

除此之外charAt()方法返回给定索引位置的字符,由传给方法的整数参数指定。具体来说,这个方法查找索引指定位置的16位码元,并返回该码元对应的字符。

let message = 'abcde';

console.log(message.charAt(2));//c

JavaScript字符串使用了两种Unicode编码混合的策略:UCS-2和UTF-16.对于可以采用16位编码的字符(u+0000~u+FFFF),这两种编码实际上是一样的。

使用charCodeAt()方法可以查看指定码元的字符编码。这个方法返回指定索引位置的码元值,索引以整数指定。比如:

let message = 'abcde';

//unicode "Latin small letter C"的编码是U+0063

console.log(message.charCodeeAt(2));//99

//十进制99等于十六进制63

console.log(99===0x63);//true

fromCharCode()方法用于根据给定的UTF-16 码元创建字符串中的字符。这个方法可以接受任意多个数值,并返回将所有数值对应的字符拼接起来的字符串:

//unicode "Latin small letter A"的编码是U+0061

//unicode "Latin small letter B"的编码是U+0062

//unicode "Latin small letter C"的编码是U+0063

//unicode "Latin small letter D"的编码是U+0064

//unicode "Latin small letter E"的编码是U+0065

console.log(String.formCharCode(0x61,0x62,0x63,0x64,0x65);//'abcde'

//0x0061 === 97

//0x0062 === 98

//0x0063 === 99

//0x0064 === 100

//0x0065 === 101

对于U+0000-U+FFFF范围内的字符,length, charAt(). charCodeAt ()和fromCharCode()返回的结果都跟预期是一样的。 这是因为在这个范围内,每个字符都是用16位表示的。而这几个方法也都基于16位码元完成操作。只要字符编码大小与码元大小对应, 这些方法就能如期工作。

字符串操作方法:

concat(),用于将一个或多个字符串拼接成一个新字符串

例:

        let str = 'hello';

        let str1 = str.concat('world');

        console.log(str);//'hello'

        console.log(str1);//'hello world'

以上例子中,对str调用concat()方法的结果得到'hello world',但str的值保持不变。concat()方法可接受任意多个参数,因此可以一次性拼接多个字符串。

例:

        let str = 'hello';

        let str1 = str.concat('world','!');

        console.log(str);//'hello'

        console.log(str1);//'hello world !'

这个修改后的例子将字符串'world'and'!'追加到了'hello'后面。虽然concat()方法可以拼接字符串,但更常用的方式是使用加号操作符(+)。而且多数情况下,对于拼接字符串来说,使用加号更方便!

从字符串中提取子字符串的方法:

slice()、substr()、substring(),这三个方法都返回调用它们的字符串的一个子字符串,而且都接收一或两个参数。第个参数表示子字符串开始的位置,第二个参数表示子字符串结束的位置。对slice()和substring()而言,第二个参数是提取结束位置(即该位置之前的字符会被提取出来)。对substr()而言,第二个参数表示返回的子字符串数量。任何情况下,省略第二个参数都意味着提取到字符串末尾。与concat()方法一样, slice()、 substr()和substring也不会修改调用它们的字符串,而只会返回提取到的原始新字符串值。来看下面的例子:

let str = 'hello world';

console.log(str.slice(3));//'lo world'

console.log(str.substring(3));//'lo world'

console.log(str.substr(3));//'lo world'

console.log(str.slice(3,7));//'lo w'

console.log(str.substring(3,7));//'lo w'

console.log(str.substr(3,7));//'lo worl'

在这个例子中,slice()、substr()和substring是以相同方式被调用的,而且多数情况下返回的值也是相同。如果只传一个参数3, 则所有方法都路将返回'lo world',因为hello中1的位置是3。如果传入两个参数3和7,则slice()和substring()则返回'lo w'(因为world中o的位置是7,不包含),而substr()返回'lo worl',因为第二个参数对它而言表示返回的字符数。

当某个参数是负值时,这三个方法的行为又不同。比如。slice()方法将所负值参数当成字符串长度加上负参数值。

而substr()方法将第一个负参数值当成字符串加上该值,将第二个参数值转换为0。substring()将所有负参数值都转换为0。

例:

        let str = 'hello world';

        console.log(str.slice(-3));//'rld'

        console.log(str.substring(-3));//'hello world'

        console.log(str.substr(-3));//'rld'

        console.log(str.slice(3,-4));//'lo w'

        console.log(str.substring(3,-4));//'hel'

        console.log(str.substr(3,-4));//' '(empty string)

这个例子确演示了3个方法的差异,在给slice() 和substr传入负参数时,它们返回的结果相同。这是因为-3会被转换为8(长度加上负参数),实际上调用的是slice(8)和substr(8)。而substring()方法返回整个字符串,因为负三会转换为0。

在第二个参数是负值时,这3个方法各不相同。slice()方法将第二个参数转换为7,实际上调用slice(3,7)因此返回'lo w'。而substring()方法会将第二个参数转换为0,相当于调用substring(3,0),等价于substring(0,3),这是因为这个方法会将较小的参数作为起点将较大的参数作为终点。对substr()来说,第二个参数会被转换为0,意味着返回的字符串包含零个字符,因而会返回一个空字符串!

字符串位置方法

有两个方法用于在字符事中定位子字符串: indexof() 和lastIndex0f()。这两个方法从字符串中搜索传入的字符串,并返回位置( 如果没找到,则返回-1)。 两者的区别在于,indexOf()方法从字符串开头开始查找子字符事,而lastIndexof ()方法从字符串末尾开始查找子字符串。

例:

        let str = 'hello world';

        console.log(str.indexOf('o'));//4

        console.log(str.lastIndexOf('o'));//7

以上例子字符串中第一个"o"的位置是4,即"hello"中的"o”。最后一个"o"的位置是7,即"world"中的"o"。如果字符串中只有一一个"o", 则indexOf ()和lastIndexOf()返回同一个位置。

这两个方法都可以接收可选的第二个参数,表示开始搜索的位置。这意味着,indeof()会从这个参数指定的位置开始向字符串末尾搜索,忽略该位置之前的字符;lastIndexOf()则会从这个参数指定的位置开始向字符串开头搜索,忽略该位置之后的字符。

例:

        console.log(str.indexOf('o',6));//7

        console.log(str.lastIndexOf('o',6));//4

以上例子在传人第二个参数6以后,结果跟前面的例子恰好相反。这一次, indexof()返回7, 因为它从位置6(字符"w" )开始向后搜索字符串,在位置7找到了“o"。而lastIndexOf()返回4,因为置6开始反向搜索至字符串开头,因此找到了"hello"中的"o”。像这样使用第二个参数并循环调用indexOf ()或lastIndexof(),就可以在字符串中找到所有的目标子字符串。

例:

        let str = "Lorem ipsum dolor sit amet ,consectetur adipisicing elit";

        let arr = [];

        let pos = str.indexOf("e");

        while(pos > -1){
                arr.push(pos);

                pos = str.indexOf("e",pos+1);

        }

        console.log(arr);//[3,24,32,35,52]

以上例子逐步增大开始搜索的位置,通过indexOf()遍历了整个字符事,首先取得第一个"e"的位置,然后进入循环,将上一次的位置加1再传给indexOf()。确保搜索到最后一个子字符串实例之后。每个位置都保存在arr数组中,可供以后使用。

字符串包含方法(ES6):

ES6增加了三个用于判断字符串中是否包含另一个字符串的方法:startsWith()、endsWith()、includes()。这些方法都会从字符串中搜索传入的字符串,并返回一个表示是否包含的布尔值。它的区别在于,staetsWith()检查开始于索引零的匹配项,endsWith()检查开始于索引(string.length-substring.length)的匹配项,而includes()检查整个字符串。

例:

        let str = 'foobarbaz';

        console.log(str.startsWith('foo'));//true

        console.log(str.startsWith('bar'));//false

        console.log(str.endsWith('baz'));//true

        console.log(str.endsWith('bar'));//false

        console.log(str.includes('bar'));//true

        console.log(str.includes('qux'));//false

startsWith()、includes()方法可接收可选的第二个参数,表示开始搜索的位置。如果传入第二个参数,则意味着这两个方法会从指定位置向着字符串末尾搜索,忽略该位置之前的字符。

例:

        let str = 'foobarbaz';

        console.log(str.startsWith('foo'));//true

        console.log(str.startsWith('foo',1));//false

        console.log(str.includes('bar'));//true

        console.log(str.includes('bar',4));//false

endsWith()方法接收可选的第二个参数,表示应该当作字符串末尾的位置。如果不提供这个参数,那么默认就是字符串长度。如果提供这个参数,那么就好像字符串只有那么多字符。

例:

         let str = 'foobarbaz';

        console.log(str.endsWith('bar'));//false

        console.log(str.endsWith('bar',6));//true

trim()方法:

ES在所有字符串上都提供了trim()方法。这个方法会创建字符串的一个副本,删除前后所有空格符,再返回结果。

例:

        let str = '   hello world   ';

        let trimmedStr = str.trim();

        console.log(str);//'   hello world   '

        console.log(trimmedStr);//'hello world'

由于trim()返回的是字符串的副本,因此原始字符串不受影响,即原本的前后空格符都会保留。

另外,trimLeft()、trimRight()方法分别用于从字符串开始和末尾清理空格!

repeat()方法:

ES在所有字符串上都提供了repeat()方法。这个方法接收一个整数参数,表示将字符串复制多少次,然后返回拼接所以副本之后的结果。

例:

        let str = 'ni';

        console.log(str.repeat(3)+'aiwo');//ni ni ni aiwo

padStart()和padEnd()方法 

padStart()和padEnd()方法 会复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件。这两个方法的第一个参数是长度,第二个参数是可选的填充字符串,默认为空格(U+0020)。

例:

        let str = 'foo';

        console.log(str.padStart(6));//'   foo'

        console.log(str.padStart(6,'.'));//'...foo'

        console.log(str.padEnd(6));//'foo   '

        console.log(str.padEnd(6,'.'));//'foo...'

可选的第二个参数并不限于一个字符。如果提供了多个字符串,则会将其拼接并截断以匹配指定长度。另外没如果长度小于或等于字符串长度,则返回原始字符串。

例:

        let str = 'foo';

        console.log(str.padStart(8,'bar'));//'barbafoo'

        console.log(str.padStart(2));//'foo'

        console.log(str.padEnd(8,'bar'));//'foobarba'

        console.log(str.padEnd(2));//'foo'

字符串迭代与解构

字符串的原型上暴露了一个@@iterator方法,表示可以迭代字符串的每个字符,可以手动使用迭代器:

例:

        let str = 'abc';

        let strIterator = str[Symbol.iterator]();

        console.log(strIterator.next());//{value:'a',doce:false}

        console.log(strIterator.next());//{value:'b',doce:false}

        console.log(strIterator.next());//{value:'c',doce:false}

        console.log(strIterator.next());//{value:undefined,doce:true}

在for—of循环中可以通过迭代器按序访问每个字符:

例:

        for(const c of 'abcde'){

                console.log(c);

        }

        //a

        //b

        //c

        //d

        //e

有了这个迭代器之后,字符串就可以通过解构操作符来解构了。比如,可以更方便的把字符串分割成字符数组。

例:

        let str = 'abcde';

        console.log([...str]);//['a','b','c','d','e']

字符串大小写转换:

有四个方法:toLowerCase()、toLocaleLowerCase()、toUpperCase()、toLocaleUpperCase()。toLowerCase()、toUpperCase()方法是原来就有的方法。toLocaleLowerCase()、toLocaleUpperCase()方法在基于特定地区实现。在很多地区,地区特定的方法与通用的方法是一样的。但在少数语言中(如土耳其语),Unicode大小写转换需应用特殊规则,要使用地区特定的方法才能实现正确转换。

例:

        let str = 'hello world';

        console.log(str.toUpperCase());//'HELLO WORLD'

        console.log(str.toLocaleUpperCase());//'HELLO WORLD'

        console.log(str.toLowerCase());//'hello world'

        console.log(str.toLocaleLowerCase());//'hello world'

以上例子,toLowerCase()、toLocaleLowerCase()都返回hello world,而toUpperCase()、toLocaleUpperCase()都返回HELLO WORLD。通常,如果不知道代码涉及什么语言,则最好使用地区特定的转换方法!

字符串模式匹配方法:

String类型专门为在字符串中实现模式匹配设计了几个方法。第一个就是 match()方法,这个方法本质上和RegExp对象的exec()方法相同。match()方法接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp对象。

例:

        let text = "cat, bat, sat, fat";

        let pattern = /.at/;

        //等价于pattern.exec(text)

        let matches = text.match(pattern);

        console.log (matches. index);//0

        console. log (matches.[0]);//'cat'

        console. log (matches.lastIndex);//0

match()方法返回的数组与RegExp对象的exec()方法返回的数组是一样的: 第一个元素是与整个模式匹配的字符串,其余元素则是与表达式中的捕获组匹配的字符串(如果有的话)。

另一个查找模式的字符串方法是 search()。这个方法唯一的参数与match()方法一样: 正则表达式字符串或RegExp对象。这个方法返回模式第一个匹配的位置索引,如果没找到则返回-1。search()始终从字符串开头向后匹配模式。

例:

        let text = "cat, bat, sat, fat";

        let pos =text.search(/at/);

        console.log(pos)//1

这里,search(/at/)返回1, 即"at"的第一个字符在字符串中的位置。

为简化字符中替换操作。ES提供了replace()方法。这个方法接收两个参数,第一个参数可以是一个RegExp对象或一个字符串(这个字符串不会转换为正则表达式),第二个参数可以是一个字符串或一个函数。如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所以子字符串,第一个参数必须为正则表达式并且带全局标记。

例:

        let text = "cat, bat, sat, fat";

        let result = text.replace("at", "ond");

        console.log(result); // "cond, bat, sat, fat"

        let result = text.replace(/at/g, "ond");

        console.log(result); // "cond, bond, sond, fond"

以上例子,字符串"at"先传给replace()函数,而替换文本是"ond"。结果是"cat"被修改为"cond",而字符串的剩余部分不变。通过将第一个参数改为带全局标记的正则表达式,字符串中的所有"at"都被替换成了"ond"!

replace()的第二个参数可以是一个函数。在只有一个匹配项时,这个函数会收到3个参数:与整个模式匹配的字符串、匹配项在字符串中的开始位置,以及整个字符串。在有多个捕获组的情况下,每个匹配捕获组的字符串也会作为参数传给这个函数,但最后两个参数还是与整个模式匹配的开始位置和原始字符串。这个函数应该返回一个字符串, 表示应该把匹配项替换成什么。使用函数作为第二个参数可以更细致地控制替换过程。

例:

        function htmlEscape(text) ({

                return text.replace(/[<>"&]/g,function(match,pos,originalText){

                        switch(match){

                                case"<":

                                        return"&lt;";

                                case">":

                                        return"&gt;";

                                case"&":

                                        return"&amp;";

                                case"\"":

                                        return"&quot;";

                        }

                })

        }

console.log (htmiEscape("<p class=\"greeting\">Hello world!</p>"));

//"&lt;p class=&quot;"greeting&quot;"&gt;Hello world!</p>"

这里,函数htmlEscape()用于将段HTML中的4个字符替换成对应的实体:小于号、大于号、和号双引号(都必须经过转义)。实现这个任务最简单的办法就是用一个正则表达式查找这些字符,然后定义一个函数,根据匹配的每个字符分别返回特定的HTML实体。

最后一个与模式匹配相关的字符串方法是split()。这个方法会根据传入的分隔符将字符串拆分成数组。作为分隔符的参数可以是字符串,也可以是RegExp对象。(字符串分隔符不会被这个方法当成正则表达式)还可以传入第二个参数,即数组大小,确保返回的数组不会超过指定大小。

例:

        let colorText = "red,blue,green,yellow";

        console.log(colorText.split(","));//["red","blue","green","yellow"]

        console.log(colorText.split(",",2));//["red","blue"]

        console.log(colorText.split(/[^,]+/));//["",",",",",",",""]

以上例子中,字符串colorText是一个逗号分隔的颜色名称字符串。调用split(",")会得到包含这些颜色名的数组,基于逗号进行拆分。要把数组元素限制为两个,传入第二个参数2即可。最后,使用正则表达式可以得到一个包含逗号的数组。注意最后此一次调用split()时,返回的数组前后包含两个空字符串。这是因为正则表达式指定的分隔符出现在了字符串开头和末尾!

localeCompare()方法:

这个方法是比较两个字符串,返回如下3个值中的一个。

        1、如果按照字母顺序字符串应该排在字符串参数前头,则返回负值。(通常是-1,具体还要看与实际值相关的实现)。

        2、如果字符串与字符串参数相等,则返回0.

        3、如果按照字母顺序字符串应该排在字符串参数后头,则返回正值。(通常是1,具体还要看与实际值相关的实现)。

例:

        let str = "yellow";

        console.log(str.localeCompare("brick"));//1

        console.log(str.localeCompare("yellow"));//0

        console.log(str.localeCompare("zoo"));//-1

以上例子,字符串"yellow"与三个不同的值进行了比较:"brick"、"yellow"、"zoo"。"brick"按字母表顺序应该排在"yellow",因此返回1。"yellow"等于"yellow",因此返回0。最后"zoo"在"yellow"后面,因此返回-1。强调一下,因为返回的具体值可能因具体实现而异,所以最好像下面一样使用localeCompare()方法:

例:

        function determineOrder(value){

                let result = str.localeCompare(value);

                if(result<0){

                        console.log(`The string 'yellow' comes before the string '${value}'.`)

                }else if(result>0){

                        console.log(`The string 'yellow' comes after the string '${value}'.`)

                }else{

                        console.log(`The string 'yellow' is equal to the string '${value}'.`)

                }

        }        

        determineOrder('brick');

        determineOrder('yellow');

        determineOrder('zoo');

这样一来,就可以保证在所有实现中都能正确判断字符串的顺序了。

localeCompare()的独特之处在于,实现所在的地区(国家和语言)决定了这个方法如何比较字符串 。在美国是ES实现的标准语言。localeCompare()区分大小写,大写字母排在小写字母前边,但其他地区未必是这种!

        

        

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:1024 设计师:我叫白小胖 返回首页
评论

打赏作者

星之仔

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值