概要
ECMAScript 的类型一共分为两大类,值类型以及引用类型。
值类型又称基础类型,具体如下:
undefined | 未定义 |
null | 空 |
boolean | 布尔 |
number | 数值 |
string | 字符串 |
symbol | 标记 |
引用类型又称复杂类型Object(对象),具体如下:
Object | 对象 |
Function | 函数 |
Array | 数组 |
RegExp | 正则 |
Date | 日期 |
基础类型
1、undefined(未定义)
undefined 类型只有一个值,在使用 var 声明变量时没初始化,此时变量值就为 undefined,在给变量初始化为 undefined 后,亦可于 undefined 等价,同时未定义的变量默认值也是undefind。
// 已定义,未初始化
var a
a // undefined
// 已定义变量,初始化为undefind
var b = undefined
b == undefined // true
// 未定义变量
c // undefined
2、null(空)
null 值表示一个空对象指针,因此在用 typeof 操作符检测 null 时会返回 "object"。
此外值得注意的一点,null 与 undefined 相互比较时返回为 true,尽管它们之间有这种关系,但它们的用途并不相同,故在多数情况下,需要对变量初始化时,用 null 代替 undefined 即可。
let a
let b = null
a == b // true
3、boolean(布尔)
boolean 类型只有两个值,分别是 true 和 false,且区分大小写,此外其它基础类型的值,在进行条件判断时会进行隐式转换,具体规则如下:
数值类型 | true | false |
Boolean | true | false |
String | 任意非空字符 | "" |
Number | 任何非零数值(包括无穷大) | 0,NaN |
Object | 任意对象 | null |
4、number(数值)
该类型可细分为整形和浮点型,同时也能表示十进制,八进制,十六进制。
八进制以0开头,且后方字符范围是 0~7;
十六进制以0x开头,且后方字符范围是(0~9及A~F),字符的大小写不受限制;
在进行算数运算时,八进制和十六进制都会转化为十进制数值
let a = 55 // 十进制
let b = 050 // 八进制
let c = 0xa // 十六进制
4.1、浮点数
所谓浮点数,就是该数字含有一个小数点,小数点后面必须有一个数字,且占用内存空间是整数的两倍,若小数点后面的值为0,则JS会将其默认转化为整型来存储。
4.2、e表示法
e为科学计数法,主要用于表示那些极大值和极小值,用e表示法的数值等于e前面的数乘以10的指数次幂,如下代码。
var a = 3.125e7 // 31250000
以上例子实际含义为: 。
如若要表示最小数,例如0.0000003,则被转化为来进行表示。
4.3、精度
在 64 位的二进制中,符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。
IEEE754 规定,有效数字第一位默认总是1 。因此,在表示精度的位数前面,还存在一个 “隐藏位” ,固定为 1 ,但它不保存在 64 位浮点数之中。也就是说,有效数字总是 1.xx…xx 的形式,其中 xx…xx 的部分保存在 64 位浮点数之中,最长为52位 。所以,JavaScript 提供的有效数字最长为 53 个二进制位,其内部实际的表现形式为:
(-1)^符号位 * 1.xx…xx * 2^指数位
这意味着,JavaScript 能表示并进行精确算术运算的整数范围为:[-253-1,253-1],即从最小值 -9007199254740991 到最大值 9007199254740991 之间的范围 。
可以通过 Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 来分别获取这个最大值和最小值。
对于超过这个范围的整数,JavaScript 依旧可以进行运算,但却不保证运算结果的精度。
浮点值的精度最高位数为17位小数,故在计算中精度远不及整数。而且在某些特定值运算时会出现精度丢失,例如:0.1+0.2=0.3000000000000004。
因此在计算浮点数时,尽可能控制小数位数,以确保值的准确性。
4.4、数值范围
JavaScript 中能表示的最大值是 1.7976931348623157 × 10308,最小值为 5 × 10-324 ,这两个边界值可以分别通过访问 Number 对象的 MAX_VALUE 属性和 MIN_VALUE 属性来获取。
Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_VALUE // 5e-324
如果数字超过最大值或最小值,JavaScript 将返回一个不正确的值,这称为 “正向溢出(overflow)” 或 “负向溢出(underflow)” 。
4.5、NaN
NaN为非数值,它是一个特殊的数值,当一个数值类型 对一个非数值类型进行运算时其结果就会返回这个特殊数值,如:3 * "s" = NaN
另外它存在两个特点:
- 任何数值对NaN进行运算,其结果都为NaN
- NaN与NaN之间并不相等
为了能更好的判断NaN,ECMAScript 定义了 isNaN() 函数,当参数是非数值类型时,返回 true,反之返回 false。
4.6、数值转换
数值类型可通过三种方法来进行强转,具体如下:
- Number() : 当字符串中含有非数字元素时,会返回 NaN
- parseInt() : 当字符串为空时返回NaN,对于含有非数字元素的字符串会进行截取操作,支持八进制与十六进制
- parseFloat() : 同上,第二个参数控制小数位数。
5、string(字符串)
string类型用于表示由0和多个16位unicode字符组成的字符序列,即字符串,可由双引号("),单引号(')表示,不过以单引号开头必须以单引号结尾,以双引号开头必须以双引号结尾。
5.1、字面量
字面量 | 含义 |
\n | 换行 |
\t | 制表 |
\b | 退格 |
\r | 回车 |
\f | 进纸 |
\\ | 斜杠 |
\' | 单引号(‘) |
\" | 双引号(”) |
\xnn | 以十六进制代码nn表示一个字符(n为0-F) |
\unnnn | 以十六进制代码nnnn表示一个unicode字符(n为0-F) |
5.2、特性
字符串的值不能改变,如要改变值,则需要先摧毁原来的值,之后在jiECMAScript 的类型一共分为两大类,值类型以及引用类型。
5.3、转换字符串
- toString():.toString 方法转换
- String() :包装类转换
- 在变量后面加上""操作符
6、symbol(标记)
由于在ES5中对象属性名都是字符串,这容易造成属性名的冲突,因此在ES6中新增类型symbol,以表明用来表示独一无二的值,用于避免属性冲突。
symbol 值通过 Symbol() 函数生成,调用 Symbol() 会返回一个独一无二的 Symbol类型的数据,具体调用代码如下:
// 直接调用
let s = Symbol()
typeof s // "symbol"
// 传参调用
let s1 = Symbol('foo');
s1 // Symbol(foo)
s1.toString() // "Symbol(foo)"
//如果参数是个对象,就会调用该对象的toString方法,将其转为字符串,然后才生成一个 Symbol 值。
const obj = {
toString() {
return 'abc'
}
}
const sym = Symbol(obj)
sym // Symbol(abc)
// Symbol 函数返回的是独一无二的,即使参数相同,亦不相同
let s2 = Symbol()
let s3 = Symbol()
s1 === s2 // false
let s4 = Symbol('foo')
let s5 = Symbol('foo')
s1 === s2 // false
注:Symbol 虽然通过方法返回生成,但并非引用类型,故不能通过 new 关键词调用。
引用类型
1、Object (对象)
引用类型仅有一个Object,它是所有对象的基础,因此所有对象都具有这些基础的属性和方法。
ECMA262 把对象定义为:无序属性的集合,其属性可以包含基本值、对象或者函数。 也就是说,对象是一组没有特定顺序的值 。由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度。
因此,对象的值存储在堆(heap)中,而存储在变量处的值,是一个指针,指向存储对象的内存处,即按址访问,具备这种存储结构的,都可以称之为引用类型 。
另外需要注意的是,ECMAScript 中对象不存在重载,如遇见同名对象实例,只会将上一个对象实例覆盖。
1.1、常用方法
- create() : 用于原型链继承,创建一个对象,并把其 prototype 属性赋值为第一个参数;
- defineProperty() : 用于定义对象属性的特性;
- defineProperties() : 用于同时定义多个属性的特性;
- getOwnPropertyNames() : 获取所有的属性名,不包括 prototy 中的属性,返回一个数组;
- keys() : 获取所有的可枚举的属性,返回一个数组;
- constructor : 当前对象的函数;
- hasOwnProperty() : 检查给定属性是否存在;
- isPrototypeOf() : 判断原型;
- assign() : 合并对象,不过是浅拷贝;
2、Function(函数)
ECMAScript 每个函数都是 Function 对象的实例,函数名是指向函数对象的指针,不会与某个函数绑定,每个函数中都存在arguments和this。
arguments用来保存函数参数,同时该函数返回中还有一个callee属性,它是一个指针,可以指向对象函数本身。
每个函数实例中都包含两个属性:length 和 prototype。
length 用于存储函数希望接收的命名参数的个数,有参数返回参数个数,无参数返回0。
prototype 用于存储函数实例方法,同时它是不可被枚举的。
每个函数实例的prototype 中都存有两个非继承方法:apply() 和 call(),它们都是用来改变函数内部 this 指向的,其区别在于调用方式不同。
function a(n1,n2){
return n1 + n2
}
function b(n1,n2){
return a.call(this, n1, n2)
// return a.apply(this, [n1,n2])
}
b(10, 10) // 20
这两个方法主要用于扩展函数依赖的作用域,减少系统的耦合程度。
3、Array(数组)
是ECMAScript中最为常用的数据之一,可动态变更长度,一个数组中可存储多种类型的数据,同时兼备排序,删除,截断,转换字符串等方法。
数组的声明也有多种方式,如下代码:
let arr = []; // 空数组
let arr1 = [1, 2, 3, 4, 5]; // 包含元素的数组
let arr2 = new Array(); // 空数组
let arr3 = new Array(1, 2, 3, 4, 5); // 包含元素的数组
let arr4 = Array.of(1, 2, 3, 4, 5); // 包含元素的数组
let arr5 = Array.from([1, 2, 3, 4, 5]); // 从其他可迭代对象创建数组
关于数组较为多样且复杂,这里就不多赘述,以下列举出一些常用的数组方法。
3.1、改变原数组的方法
- push()末尾添加数据
- pop()末尾处删除数据
- unshift()头部添加数据
- shifr()头部删除数据
- reverse()翻转数组
- sort()排序
- splice()截取数组
3.2、不改变原数组的方法
3.3、ES6新增的数组方法
- forEach()用来循环遍历的for
- map() 映射数组的
- filter() 过滤数组
- every() 判断数组是不是满足所有条件
- some()数组中有没有满足条件的
- find()用来获取数组中满足条件的第一个数据
- reduce()叠加后的效果
4、RegExp(正则)
ECMAScript 中通过RegExp对象来实现正则表达式,使用类似Perl的语法创建,以下列出一个简单的例子。
let regex = /\d+/; // 使用正则表达式字面量
let regex = new RegExp('\\d+'); // 使用RegExp构造函数
let regex = new RegExp('pattern', 'gi'); // 带有标志的正则表达式
4.1、正则表达式支持三种模式标识:
- g:全局模式,即将被应用至整个匹配字符串中,发现一个匹配失败,立刻停止
- i:不区分大小写模式,即忽略英文大小写
- m:多行模式,即达到文本末尾后自动配备下一行
除了以上三种标识外,正则表达式还包含其余标识,以下列出些常用标识,以供查阅:
字符 | 描述 |
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“n”匹配字符“n”。“\n”匹配一个换行符。序列“\\”匹配“\”而“\(”则匹配“(”。 |
^ | 匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。 |
$ | 匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。 |
* | 匹配前面的子表达式零次或多次。例如,zo*能匹配“z”以及“zoo”。*等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。 |
? | 匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”中的“do”。?等价于{0,1}。 |
{n} | n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。 |
{n,} | n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。 |
{n,m} | m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。 |
? | 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。 |
. | 匹配除“\``n”之外的任何单个字符。要匹配包括“\``n”在内的任何字符,请使用像“[.\``n``]”的模式。 (pattern) 匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“\(”或“\)”。 |
(?:pattern) | 匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“`( |
(?=pattern) | 正向预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“`Windows(?=95 |
(?!pattern) | 负向预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如“`Windows(?!95 |
x|y | 匹配x或y。例如,“`z |
[xyz] | 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。 |
[^xyz] | 负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“p”。 |
[a-z] | 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。 |
[^a-z] | 负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。 |
\B | 匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。 |
\cx | 匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c”字符。 |
\d | 匹配一个数字字符。等价于[0-9]。 |
\D | 匹配一个非数字字符。等价于[^0-9]。 |
\f | 匹配一个换页符。等价于\x0c和\cL。 |
\n | 匹配一个换行符。等价于\x0a和\cJ。 |
\r | 匹配一个回车符。等价于\x0d和\cM。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[\f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于[^\f\n\r\t\v]。 |
\t | 匹配一个制表符。等价于\x09和\cI。 |
\v | 匹配一个垂直制表符。等价于\x0b和\cK。 |
\w | 匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_]”。 |
\W | 匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。 |
\xn | 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“\x41”匹配“A”。“\x041”则等价于“\x04&1”。正则表达式中可以使用ASCII编码。. |
\num | 匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字符。 |
\n | 标识一个八进制转义值或一个向后引用。如果\n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n为一个八进制转义值。 |
\nm | 标识一个八进制转义值或一个向后引用。如果\nm之前至少有nm个获得子表达式,则nm为向后引用。如果\nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若n和m均为八进制数字(0-7),则\nm将匹配八进制转义值nm。 |
\nml | 如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。 |
\un | 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹配版权符号(?) |
正则具体匹配可参考最全常用正则表达式大全,这里不多赘述。
4.2、RegExp对象的实例属性
- global: 布尔,判断是否设置 g 标识
- ignoreCase: 布尔,判断是否设置 i 标识
- lastIndex: 整数,标识开始匹配搜索下一个匹配项字符的位置,从0算起
- multiline: 布尔,是否设置了m标志
- source: 正则的字符串表示,将正则表示式以字符串输出出来。
4.3、 RegExp对象的实例方法
在 RegExp对象中包含两个实例方法,分别是 exec() 和 test()。
exec() 主要用于捕获字符串匹配信息,它可以接收一个参数,然后返回包含第一个匹配信息的数组,而test()则用来验证字符串是否符合匹配规则,下面我列出两个方法的使用例子,以供各位看官理解。
4.4、exec()
基础匹配
let regex = /foo/;
let str = 'foobar';
let result = regex.exec(str);
console.log(result); // 输出:["foo", index: 0, input: "foobar", groups: undefined]
带有全局标志的匹配
let regex = /foo/g; // 注意 'g' 标志,表示全局搜索
let str = 'foo, foo, foo';
let result;
while ((result = regex.exec(str)) !== null) {
console.log(result);
}
// 输出:
// ["foo", index: 0, input: "foo, foo, foo", groups: undefined]
// ["foo", index: 5, input: "foo, foo, foo", groups: undefined]
// ["foo", index: 10, input: "foo, foo, foo", groups: undefined]
带有捕获组的匹配
let regex = /(\d+)-(\w+)/;
let str = '123-abc';
let result = regex.exec(str);
console.log(result);
// 输出:["123-abc", "123", "abc", index: 0, input: "123-abc", groups: undefined]
使用 lastIndex
属性
let regex = /foo/g;
let str = 'foo foo foo';
let result1 = regex.exec(str);
let result2 = regex.exec(str);
console.log(result1.index); // 输出:0
console.log(result2.index); // 输出:5
console.log(regex.lastIndex); // 输出:9
4.5、test()
基础匹配
let regex = /foo/;
let str = 'foobar';
let result = regex.test(str);
console.log(result); // 输出:true
不区分大小写的匹配
let regex = /foo/i; // 'i' 标志表示不区分大小写
let str1 = 'FOObar';
let str2 = 'foobaz';
let result1 = regex.test(str1);
let result2 = regex.test(str2);
console.log(result1); // 输出:true
console.log(result2); // 输出:true
全局搜索标志与 test()
let regex = /foo/g; // 'g' 标志表示全局搜索
let str = 'foo foo foo';
let result1 = regex.test(str);
let result2 = regex.test(str);
console.log(result1); // 输出:true
console.log(result2); // 输出:true
使用捕获组进行匹配
let regex = /(\d+)-(\w+)/;
let str1 = '123-abc';
let str2 = 'no-match';
let result1 = regex.test(str1);
let result2 = regex.test(str2);
console.log(result1); // 输出:true
console.log(result2); // 输出:false
注:捕获组是正则表达式中的一种特殊语法,用于在匹配过程中捕获和提取特定的子字符串。
5、Date(时间)
时间对象在开发过程中也是较为常用的类型,下面简单说一下关于时间对象的属性以及应用。
在 ECMAScript 中 Data 对象能构建时间对象实例,在没有传参的情况下,返回对象是当前时间信息。如果想根据已有时间,构建时间对象,则需要在初始化时,进行参数传递。
var a = new Date() // 当前时间
var b = new Date("2013-5-30") // 指定时间
如果要获取当前时间的时间戳(毫秒),可以通过静态方法 now() 来实现。
Date.now()
常用实例方法:
- getTime() : 日期毫秒数
- getFullYear() : 四位数年份
- getMonth() : 月,0-11,0表示一月,11表示十二月
- getDate() : 日,1-31
- getDay() : 周几,0-6,0表示周日,6表示周六
- getHours() : 时,0-23
- getMinutes() : 分,0-59
- getSeconds() : 秒,0-59
- getMilliseconds() : 毫秒
存储区别
基础类型和引用类型出了以上特性的不同外,在存储上也存在一些差异。
基础类型的变量是直接存储在内存中的,而引用类型变量保存的是地址,而非变量本身,读取引用类型变量读取地址,在通过地址找到对象在内存中存储的位置。
因此哪怕是同为空的数组,也并不相同。
let a = []
let b = []
a === b // false
再例如两个地址指向同一个变量时,出现修改c变量的值,导致b的值也跟着发生了改变的情况,如下例子。
let b = [{user:1,name:3},{user:2,name:4}]
let c = b.filter(v => v.user == 1)
c[0].name = 'xiaomin'
b // [{user:1,name:'xiaomin'},{user:2,name:4}]
总结:
JS中的数据类型虽然与其它语言有所不同,但在某些地方还是互通的,只是更加多样和灵活了些,同时各种API以及常用方法,也让对变量的操作更加便捷些。
感谢观看,创作不易,如有纰漏望各位看官多加指正。
标签:regex,字符,匹配,JavaScript,数据类型,let,数组,foo From: https://blog.csdn.net/qq_35078336/article/details/139512650