跳至主要内容

JavaScript从零开始——数据类型(3)

 书接上文,这次因为要处理邮件什么的更新晚了几天,今天把它补上。

之前了解过了数值,现在轮到了文本——字符串:

1 定义

1.1 基础字符串

在JavaScript当中,字符串就是放在两个单引号或者双引号当中的零个或多个字符,比如:

''
"test"
'Strings'
"!!!"

在单引号或者双引号内部,也可以分别使用对方,比如,单引号内使用双引号,或者双引号内使用单引号,如:

'This is a "test"!'
"This is another 'test'!"

而如果要在单引号内使用单引号,或者双引号内使用双引号,则需要加上\(反斜杠)进行转义,如:

'It\'s a beautiful day!'
"Should I say \"Hello\" to him?"

惯例上,由于HTML使用双引号标识属性,开发者会自觉在JavaScript当中使用单引号标识字符串;我自然也不例外。不过并不排除有人会喜欢使用双引号进行标识,当然这也是可以的,不过在实际开发过程当中,最好始终保持同一种风格,而不要一时使用单引号,一时使用双引号。

另外,从ES 6版本开始,JavaScript支持了新的写法——模板字符串(template string)是增强版的字符串,用反引号`标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量:

同样的,如果需要在模板字符串内(即两个反引号``内)使用反引号,需要加上反斜杠进行转义:

比较特殊的地方在于,模板字符串内的字符串可以保持换行、缩进的多少:

最后,在模板字符串内部,使用${}可以直接调用变量、表达式,这样的使用减少了字符串+变量/表达式的拼接,实在是居家旅行之必备方式:

1.2 字符串拼接

实际使用中,其实会有很多情况下需要使用多组字符串进行拼接,不过如果直接在引号当中分行,是会报错的,如:

这种时候,如果仅仅只是想生成单行字符串,可以在每行字符结尾添加\(反斜杠),这样会直接生成单行字符串且不报错,如:

或者也可以使用+号进行字符串拼接,如:

如果想保持原样多行输出,除了下文即将提出的换行转义符\n,其实也可以采用一种利用注释的变通方法,如下:

不过可以从后续的方法看出,\n仍然是分行的基础,故而这种方式太过繁复,并不建议。

在ES 6引入模板字符串之后,这个问题变得更容易解决了,因为在反引号``内部本身就已经支持了多行文本,以及变量调用;在有可能的情况下,建议尽量使用模板字符串。

2 转义

在字符串构造的时候,其实需要很多特殊的功能,包括换行、制表、换页、回车等等,直接使用字符串本身是无法构造成功的,故而需要转义符的存在——特殊字符\(反斜杠);下面用一个简单的列表把相关功能标示出来:

  • \0 :null(\u0000
  • \b :后退键(\u0008
  • \f :换页符(\u000C
  • \n :换行符(\u000A
  • \r :回车键(\u000D
  • \t :制表符(\u0009
  • \v :垂直制表符(\u000B
  • \' :单引号(\u0027
  • \" :双引号(\u0022
  • \\ :反斜杠(\u005c

举个简单的例子:

上图中使用了制表符\t以及换行符\n,同时为了代码易读性,分成了两行编写,并使用了\将其连接,最终结果就是分为了两行三列的建议表单。

除上面的情况之外,其实还有三种比较特殊的用法,本质上都是引用了Unicode的码点:

  • \000 - \777 —— 在反斜杠后包括3位的8进制数值,也可以代表不同的特殊符号,从000到777共256种,简单举例如下图:
  • \x00 - \xFF —— 在反斜杠后加上小写字母x,以及2位的16进制数值,从00到FF也是256种,简单举例如下图:
  • \u0000 - \uFFFF —— 在反斜杠后加上小写字母u,以及4位的16进制数值,从0000到FFFF共65536种,这也就有可能添加上了各种东方语言文字,比如\uB000就是韩语的”뀀“:

这里需要补充一点,ES 6开始支持了更高位数的十六进制unicode字符,只需要使用大括号{}将其括住即可正确识别,下图就是使用大括号和不使用大括号的对比:

有了如上的方法之后,JavaScript从ES 6版本开始,拥有了6种表示同一个字符的方式:

当然转义符如果用在了非预先定义的字符上时,就可能被引擎直接忽略掉,如:

3 字符串与数组

在JavaScript的定义当中,字符串其实也可以考虑为字符数组(数组的概念之后会涉及到),因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始),譬如:

如果方括号中的数字超过字符串的长度,或者方括号中根本不是数字,则返回undefined

不过字符串可以当成是有只读属性的数组,故而无法通过该方式修改其中的单个字符:

在普通模式下,尽管并未报错,但这些修改都默默地失败了,哈哈……

而在严格模式下,则会产生如下错误提示:

4 length属性

与数组相同,字符串也可以使用length看到成员的个数,并同样是只读属性:

5 字符集

JavaScript 使用 Unicode 字符集。JavaScript 引擎内部,所有字符都用 Unicode 表示。

JavaScript 不仅以 Unicode 储存字符,还允许直接在程序中使用 Unicode 码点表示字符,即将字符写成\uxxxx的形式,其中xxxx代表该字符的 Unicode 码点。比如,\u00A9代表版权符号。

解析代码的时候,JavaScript 会自动识别一个字符是字面形式表示,还是 Unicode 形式表示。输出给用户的时候,所有字符都会转成字面形式。

上面代码中,第一行的变量名foo是 Unicode 形式表示,第二行是字面形式表示。JavaScript 会自动识别。

我们还需要知道,每个字符在 JavaScript 内部都是以16位(即2个字节)的 UTF-16 格式储存。也就是说,JavaScript 的单位字符长度固定为16位长度,即2个字节。

但是,UTF-16 有两种长度:对于码点在U+0000到U+FFFF之间的字符,长度为16位(即2个字节);对于码点在U+10000U+10FFFF之间的字符,长度为32位(即4个字节),而且前两个字节在0xD8000xDBFF之间,后两个字节在0xDC000xDFFF之间。举例来说,码点U+1D306对应的字符为 ,它写成 UTF-16 就是0xD834 0xDF06

JavaScript 对 UTF-16 的支持是不完整的,由于历史原因,只支持两字节的字符,不支持四字节的字符。这是因为 JavaScript 第一版发布的时候,Unicode 的码点只编到U+FFFF,因此两字节足够表示了。后来,Unicode 纳入的字符越来越多,出现了四字节的编码。但是,JavaScript 的标准此时已经定型了,统一将字符长度限制在两字节,导致无法识别四字节的字符。上一节的那个四字节字符 ,浏览器会正确识别这是一个字符,但是 JavaScript 无法识别,会认为这是两个字符。

上面代码中,JavaScript 认为 的长度为2,而不是1。

总结一下,对于码点在U+10000U+10FFFF之间的字符,JavaScript 总是认为它们是两个字符(length属性为2)。所以处理的时候,必须把这一点考虑在内,也就是说,JavaScript 返回的字符串长度可能是不正确的。

6 Base64转码

有时,文本里面包含一些不可打印的符号,比如 ASCII 码0到31的符号都无法打印出来,这时可以使用 Base64 编码,将它们转成可以打印的字符。另一个场景是,有时需要以文本格式传递二进制数据,那么也可以使用 Base64 编码。

所谓 Base64 就是一种编码方法,可以将任意值转成 0~9A~Za-z+/这64个字符组成的可打印字符。使用它的主要目的,不是为了加密,而是为了不出现特殊字符,简化程序的处理。

JavaScript 原生提供两个 Base64 相关的方法。

  • btoa():任意值转为 Base64 编码
  • atob():Base64 编码转为原来的值

注意,这两个方法不适合非 ASCII 码的字符,会报错。

要将非 ASCII 码字符转为 Base64 编码,必须中间插入一个转码环节,再使用这两个方法。

图中的错误是因为我不小心引用了错误的方法,抱歉抱歉

其中encodeURIComponent()以及decodeURIComponent()两个方法是用来对非ASCII字符进行转换的,这样可以保证得到的结果是可以由btoa()以及atob()识别的。

这里主要描述的是数据类型,故而一些针对字符串对象的方法,先略过,后文提及对应对象的时候,再详细解释,省的这文章太过复杂,毕竟是”从零开始“么。

评论

此博客中的热门博文

Web API从零开始——SVG

SVG 是我基本没有用过的知识块,所以这里也是边分享边学习,尽量在我自己理解的基础上来分享。 1 概念 SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector Graphics);其他图像格式都是基于像素处理的, SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。 SVG 文件可以直接插入网页,成为 DOM 的一部分,然后用 JavaScript 和 CSS 进行操作。 上面是 SVG 代码直接插入网页的例子。 SVG 代码也可以写在一个独立文件中,然后用 、 、 、 等标签插入网页: < img src = "circle.svg" > < object id = "object" data = "circle.svg" type = "image/svg+xml" ></</span> object > < embed id = "embed" src = "icon.svg" type = "image/svg+xml" > < iframe id = "iframe" src = "icon.svg" ></</span> iframe > CSS 也可以使用 SVG 文件: . logo { background : url ( icon.svg ); } SVG 文件还可以转为 BASE64 编码,然后作为 Data URI 写入网页: < img src = "data:image/svg+xml;base64,[data]" > 2 语法 2.1 标签 我们可以把 SVG 代码都放在顶层标签 之中,下面是一个例子: < svg width = "100%" height = "100%" > ...

Node.js从零开始——事件、系统和流

毕竟不是一个真正的教程,这里主要还是以普及和介绍为主,所以这一部分就是 Node.js 的其他部分介绍了,主要也就是事件触发、操作系统以及流的知识。 1 事件触发器 因为我们之前在浏览器中使用 JavaScript ,所以知道 JS 通过事件处理了许多用户的交互:鼠标的单击、键盘按钮的按下、对鼠标移动的反应等等。 在后端, Node.js 也提供了使用 events 模块 构建类似系统的选项。 具体上,此模块提供了 EventEmitter 类,用于处理事件。 使用以下代码进行初始化: const EventEmitter = require ( 'events' ); const eventEmitter = new EventEmitter (); 该对象公开了 on 和 emit 方法: emit 用于触发事件 on 用于添加回调函数(会在事件被触发时执行) 例如,创建 start 事件,并提供一个示例,通过记录到控制台进行交互: eventEmitter . on ( 'start' , () => { console . log ( '开始' ); }); 当运行以下代码时: eventEmitter . emit ( 'start' ); 事件处理函数会被触发,且获得控制台日志。 可以通过将参数作为额外参数传给 emit() 来将参数传给事件处理程序: eventEmitter . on ( 'start' , number => { console . log ( `开始 ${ number } ` ); }); eventEmitter . emit ( 'start' , 23 ); 多个参数: eventEmitter . on ( 'start' , ( start , end ) => { console . log ( `从 ${ start } 到 ${ end } ` ); }); eventEmitter . emit ( 'start' ,...

JavaScript从零开始——入门(1)

  正好这段时间在学习JavaScript全栈,顺便把自己到目前为止的知识重新整理一下,做个自己能够理解的学习路径出来。 先从入门开始,老生常谈一下5W1H——有很大一部分,尤其是历史是引用自网道的JavaScript教程,特此声明: 入门篇 ​ wangdoc.com What——什么是JavaScript? 各个网站、书籍、教程都写了无数次JavaScript的定义,最简单的一种说法就是: JavaScript是一种轻量级的脚本语言。 其实这个定义到2020的今天,有一点点不太一样了,毕竟它已经发展到一个前人无法想象的地步了,如今的JavaScript不再是只能用来编写控制其他大型应用程序的“脚本”,它还可以用来构建服务器(如最常用的Web服务器等),构造移动应用(主流的iOS或者Android),甚至可以直接编写PC端桌面应用(Windows,Mactintosh以及Linux),已经是不折不扣的“全栈”语言了。 当然其实它所提供的核心语法并不算很多,只能用来做一些数学和逻辑运算,也不提供任何与I/O相关的API,而是要靠宿主环境(host)提供,所以它其实算是 嵌入式(embedded)语言 ,现如今这诸多用途的开发,都是各大JavaScript框架的功劳:譬如服务器构建,用到了著名的Node.js;移动应用上常见的是React Native,PhoneGap/Cordova甚至jQuery Mobile;桌面应用的框架则主要是electron.js。 最后,从语法角度看,它是一种 “对象模型”语言 ,各种宿主环境通过这个模型,描述自己的功能和操作接口,从而通过JavaScript来控制对应功能;但JavaScript并不是纯粹的“面向对象的”语言,因为它还支持其他的编程范式——如函数式编程——这就导致几乎任何问题,它都可能有多种解决的方法。 Where——JavaScript可以用在哪里? 如前所述,JavaScript的核心语法其实很精简,只包括了: 基本的语法构造 :操作符、控制结构、语句等; 标准库 :Array(数组)、Date(日期时间)、Math(数学库)等等。 除此之外的所有其他特性,都是由宿主所提供的API,仅仅是通过JavaScript进行调用。 如浏览器,它额外提供了如下三大类API: 浏览器控制类: 操作浏览器 DOM(文档对...