JavaScript-标准对象

标准对象

JS中,一切皆对象.

使用typeof操作符可以获取对象类型.

1
2
3
4
5
6
7
8
9
10
11
typeof 123; // 'number'
typeof 123n; // 'bigint'
typeof NaN; // 'number'
typeof 'str'; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof Math.abs; // 'function'
// object
typeof null; // 'object'
typeof []; // 'object'
typeof {}; // 'object'

null,array,通常意义的对象{}都是object

包装对象

除了上面的类型,JS还提供包装对象.

1
2
3
4
5
6
7
8
typeof new Number(123); // 'object'
new Number(123) === 123; // false

typeof new Boolean(true); // 'object'
new Boolean(true) === true; // false

typeof new String('str'); // 'object'
new String('str') === 'str'; // false

虽然包装对象的出来的值可以与原来的保持一致,但是对象类型一律都会变为object,如果与原始值用===比较会返回false.

所以不要使用包装对象!尤其是针对string类型

new 操作符主要用于创建一个用户定义的对象类型的实例,如果不用new, Number(),Boolean(),String()就会被当做普通函数,把任何类型的数据转换成Number,Booleanstring.

1
2
3
4
5
6
7
8
9
10
11
let n = Number('123'); // 123,相当于parseInt()或parseFloat()
typeof n; // 'number'

let b = Boolean('true'); // true
typeof b; // 'boolean'

let b2 = Boolean('false'); // true! 'false'字符串转换结果为true!因为它是非空字符串!
let b3 = Boolean(''); // false

let s = String(123.45); // '123.45'
typeof s; // 'string'

总结一下:

  1. 不要使用new Number(),new Boolean(),new String()创建包装对象

  2. parseInt()parseFloat()来转换任意类型到number

  3. String()或来转换任意类型到string,或者直接调用对象的toString()方法

    1. 除了nullundefined,任何对象都有toString()方法

    2. number对象直接调用toString方法会报错,需要用两个点或者加括号来调用

      1
      2
      3
      123.toString(); // SyntaxError
      123..toString(); // 正确
      (123).tiString(); // 正确

      不要问为什么,这就是JS.

  4. 通常不用把任意类型转换成boolean再判断,可以直接写if (myVar) {...}

  5. typeof可以判断出numberbooleanstringfunctionundefined

  6. 判断Array是使用Array.isArray(arr)

  7. 判断null请使用myVar === null

  8. 判断某个全局变量是否存在使用typeof window.myVar === 'undefined'

  9. 函数内部判断某个变量是否存在typeof myVar == 'undefined'

Date

Date对象用来表示日期和时间

1
2
3
4
5
6
7
8
9
10
11
12
// 通过浏览器获取系统时间
let now = new Date();
now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
now.getFullYear(); // 2015, 年份
now.getMonth(); // 5, 月份,注意月份范围是0~11,5表示六月
now.getDate(); // 24, 表示24号
now.getDay(); // 3, 表示星期三
now.getHours(); // 19, 24小时制
now.getMinutes(); // 49, 分钟
now.getSeconds(); // 22, 秒
now.getMilliseconds(); // 875, 毫秒数
now.getTime(); // 1435146562875, 以number形式表示的时间戳

新建一个指定日期时间的Date对象

1
2
let d = new Date(2015, 5, 19, 20, 15, 30, 123);
console.log(d); // Fri Jun 19 2015 20:15:30 GMT+0800 (CST)

**注意:**是的没错,JS的月份范围是0-11,0一月份.

第二种创建指定日期和时间的方法是: 解析一个符合ISO 8601格式的字符串

1
2
3
4
5
let d = Date.parse('2015-06-24T19:49:22.875+08:00');
console.log(d); // 1435146562875 返回的是一个时间戳
let d = new Date(1435146562875); // 通过时间戳就能很容易转换成Date
d; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
d.getMonth(); // 5

**注意:**是的没错,获取的月份会-1

这是一个很坑爹的设计,估计当时JS设计者脑子一抽写成这样,但是现在要改回来已经是不可能了.

时区

date对象表示的时间总是按浏览器所在时区显示.

1
2
3
4
5
6
7
let d = new Date(1435146562875);
d.toLocaleString(); // '2015/6/24 下午7:49:22',本地时间(北京时区+8:00),显示的字符串与操作系统设定的格式有关
d.toUTCString(); // 'Wed, 24 Jun 2015 11:49:22 GMT',UTC时间,与中国本地时间相差8小时

// 获取当前时间戳
console.log(Date.now());
console.log(new Date().getTime());

正则表达式

教程

在线测试+语法参考

RegExp

JS中使用正则有两种方式:

  1. /正则表达式/
  2. new RegExp('正则表达式')
1
2
3
4
5
let re1 = /ABC\-001/;
let re2 = new RegExp('ABC\\-001');

re1; // /ABC\-001/
re2; // /ABC\-001/

第二种写法中,字符串转义,所以是\\

不论那种写法,都是RegExp对象.

匹配

test()方法判断是否匹配

1
2
3
4
let re = /^\d{3}\-\d{3,8}$/;
re.test('010-12345'); // true
re.test('010-1234x'); // false
re.test('010 12345'); // false

切分字符串

1
'a b   c'.split(/\s+/); // ['a', 'b', 'c']

\s: 匹配空格

+: 至少一个

1
'a,b, c  d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd']

[\s\,]空格或者逗号

1
'a,b;; c  d'.split(/[\s\,\;]+/); // ['a', 'b', 'c', 'd']

分组

()表示要提取的分组(Group)

1
2
3
let re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-12345'); // ['010-12345', '010', '12345']
re.exec('010 12345'); // null

如果正则中定义了组,就可以在RegExp对象上用exec()方法提取子串.

exec()匹配成功会返回一个Array,第一个元素就是整个字符串,后面就是匹配成功的分组子串

exec()匹配失败返回null

下面看一个识别合法时间的例子:

1
2
let re = /^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$/;
re.exec('19:05:30'); // ['19:05:30', '19', '05', '30']

正则表达有时候写起来其实会很复杂,但是现在有AI.

贪婪匹配

正则默认是贪婪匹配模式: 匹配尽可能多的字符

1
2
let re = /^(\d+)(0*)$/; 
re.exec('102300'); // ['102300', '102300', '']

可以看到\d+采用贪婪匹配,所以把后面的0全匹配了,所以0*就什么都匹配不到.

通过在量词后面加?停止贪婪匹配(尽可能少匹配)

1
2
let re = /^(\d+?)(0*)$/;
re.exec('102300'); // ['102300', '1023', '00']

非贪婪会导致更多回溯,也就是更多的性能消耗,所以尽可能用更精确的pattern而不是用非贪婪.

全局匹配

JS的特殊标记: g表示全局匹配

1
2
3
let r1 = /test/g;
// 等价于:
let r2 = new RegExp('test', 'g');

全局匹配通过多次执行exec()方法来搜索匹配到的字符.另外每次执行exec(),都会更新lastIndex属性,表示本次匹配到的最后索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let s = 'JavaScript, VBScript, JScript and ECMAScript';
let re=/[a-zA-Z]+Script/g;

// 使用全局匹配:
re.exec(s); // ['JavaScript']
re.lastIndex; // 10

re.exec(s); // ['VBScript']
re.lastIndex; // 20

re.exec(s); // ['JScript']
re.lastIndex; // 29

re.exec(s); // ['ECMAScript']
re.lastIndex; // 44

re.exec(s); // null,直到结束仍没有匹配到

全局匹配类似搜索,所以不能使用/^...$/,那样只会最多匹配一次.

其他标志:

  • i标志: 忽略大小写
  • m标志: 执行多行匹配

JSON

全称: JavaScript Object Notation,是一种数据交换格式.

在JSON出现之前,大家一直用XML来传递数据。因为XML是一种纯文本格式,所以它适合在网络上交换数据。XML本身不算复杂,但是,加上DTD、XSD、XPath、XSLT等一大堆复杂的规范以后,任何正常的软件开发人员碰到XML都会感觉头大了,最后大家发现,即使你努力钻研几个月,也未必搞得清楚XML的规范。

终于,在2002年的一天,道格拉斯·克罗克福特(Douglas Crockford)同学为了拯救深陷水深火热同时又被某几个巨型软件企业长期愚弄的软件工程师,发明了JSON这种超轻量级的数据交换格式.

JSON实际上JS的一个子集.在JSON中,一共就这么几种数据类型:

  • number:和JavaScript的number完全一致;
  • boolean:就是JavaScript的truefalse
  • string:就是JavaScript的string
  • null:就是JavaScript的null
  • array:就是JavaScript的Array表示方式——[]
  • object:就是JavaScript的{ ... }表示方式。
  • 以及上面的任意组合.

同时JSON定死了字符集必须是UTF-8,支持多语言.字符串和object的键也规定一定要使用"",统一解析.

几乎所有语言都有解析JSON的库,在JS中,可以直接使用JSON,因为JS内置解析.

序列化

将编程语言的数据类型转成JSON类型,称为序列化.

1
2
3
4
5
6
7
8
9
10
11
12
let xiaoming = {
name: '小明',
age: 14,
gender: true,
height: 1.65,
grade: null,
'middle-school': '\"W3C\" Middle School',
skills: ['JavaScript', 'Java', 'Python', 'Lisp']
};

let s = JSON.stringify(xiaoming, null, ' '); // 直接使用JSON
console.log(s);

第二个参数可用于筛选对象键值,比如只想输出nameskills:

1
JSON.stringify(xiaoming, ['name', 'skills']. '  ');

还可以传入一个函数,对象的每个键值对都会被函数优先处理

1
2
3
4
5
6
7
8
function convert(key, value) {
if (typeof value == 'string') {
return value.toUpperCase();
}
return value;
}

JSON.stringify(xiaoming, convert, ' ') // 把所有字符串的value转为大写

第三个参数表示缩进,上面表示每层缩进两个空格.

还可以通过定义一个toJSON的方法,精确控制JSON想要序列化的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let xiaoming = {
name: '小明',
age: 14,
gender: true,
height: 1.65,
grade: null,
'middle-school': '\"W3C\" Middle School',
skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
toJSON: function () {
return { // 只输出name和age,并且改变了key:
'Name': this.name,
'Age': this.age
};
}
};

JSON.stringify(xiaoming); // '{"Name":"小明","Age":14}'

反序列化

将JSON转换成编程语言的对象,称为反序列化

JS使用JSON.parse()实现

1
2
3
4
JSON.parse('[1,2,3,true]'); // [1, 2, 3, true]
JSON.parse('{"name":"小明","age":14}'); // Object {name: '小明', age: 14}
JSON.parse('true'); // true
JSON.parse('123.45'); // 123.45

可以看出JSON.parse()不仅可以转化json.

它还可以接收一个函数,用来转换解析出来的属性

1
2
3
4
5
6
7
let obj = JSON.parse('{"name":"小明","age":14}', function (key, value) {
if (key === 'name') {
return value + '同学';
}
return value;
}); // 将JSON转成JS对象
console.log(JSON.stringify(obj)) // 将JS对象转成JSON字符串

JavaScript-标准对象
http://example.com/2024/11/11/js-standar-object/
作者
Peter Pan
发布于
2024年11月11日
许可协议