第09章 内置对象

199 阅读10分钟

一、Date

Date 对象是JavaScript提供的日期和时间的操作接口。它可以表示的时间范围是,1970年1月1日00:00:00 前后的各1亿天(单位为毫秒(ms))。

Date 对象可以作为普通函数直接调用,返回一个代表当前时间的字符串。即使带有参数,Date 作为普通函数使用时,返回的还是当前时间。

Date()
// Tue Jul 04 2017 10:15:15 GMT+0800 (CST)

Date(2017, 07, 16)
// Tue Jul 04 2017 10:15:15 GMT+0800 (CST)

1. 创建日期 *

a. new Date(); *
b. new Date(value);
c. new Date(dateString); *
d. new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);

语法解读:

  • a:根据当前时间创建日期对象
  • b:参数为相距 “1970年1月1日00:00:00” 的毫秒数
  • c:参数为日期格式字符串,如:“2019, Aug 20 19:20:35”、“2019/08/20 19:20:35”
  • d:参数分别为 -> 年、月、日、时、分、秒、毫秒,年、月不能省略,月份从0开始计算。

2. 日期运算 *

类型转换时,Date 对象的实例如果转为数值,则等于对应的毫秒数;如果转为字符串,则等于对应的日期字符串。所以,两个日期对象进行减法运算,返回的就是它们间隔的毫秒数;进行加法运算,返回的就是连接后的两个字符串。

var d1 = new Date(2019, 2, 1);
var d2 = new Date(2019, 3, 1);

d2 - d1
// 2678400000

d2 + d1
// "Sat Apr 01 2000 00:00:00 GMT+0800 (CST)Wed Mar 01 2000 00:00:00 GMT+0800 (CST)"

3. 静态方法

  • Date.now()

    Date.now() 方法返回当前距离1970年1月1日 00:00:00 UTC的毫秒数(Unix时间戳乘以1000)。

    Date.now(); // 1488604011929
    

    如果需要比毫秒更精确的时间,可以使用 window.performance.now()。它提供页面加载到命令运行时的已经过去的时间,可以精确到千分之一毫秒。

    window.performance.now(); // 5496790.340000001
    
  • Date.parse()

    Date.parse 方法用来解析日期字符串,返回距离1970年1月1日 00:00:00的毫秒数。

    标准的日期字符串的格式,应该完全或者部分符合RFC 2822和ISO 8061,即 ‘YYYY-MM-DDTHH:mm:ss.sssZ’ 格式,其中最后的Z表示时区。但是,其他格式也可以被解析,请看下面的例子。

    Date.parse('Aug 7, 2019') 
    

    如果解析失败,返回 NaN

    Date.parse('xxx') // NaN
    

4. 实例方法

Date 的实例对象方法有很多,分为以下三类。

  • to 类:日期转换
  • get类:获取日期信息
  • set类:设置日期信息

# to类方法

var d = new Date();

d.toString(); 			// "Wed Aug 07 2019 09:55:23 GMT+0800 (中国标准时间)"
d.toUTCString(); 		// "Wed, 07 Aug 2019 01:55:23 GMT"
d.toISOString(); 		// "2019-08-07T01:55:23.251Z"
d.toJSON(); 			// "2019-08-07T01:55:23.251Z"
d.toDateString(); 		// "Wed Aug 07 2019"
d.toTimeString(); 		// "09:55:23 GMT+0800 (中国标准时间)"
d.toLocaleDateString(); // "2019/8/7"
d.toLocaleTimeString(); // "上午9:55:23"
d.toLocaleString();     // "2019/8/7 上午9:55:23"

# get类方法

Date对象提供了一系列 get 方法,用来获取实例对象某个方面的值。

  • getTime():返回距离 1970年1月1日00:00:00 的毫秒数。
  • getDate():返回号数。
  • getDay():返回星期几,星期日为0,星期一为1,以此类推。
  • getYear():返回距离1900的年数。
  • getFullYear():返回四位的年份。
  • getMonth():返回月份(0表示1月,11表示12月)。
  • getHours():返回小时(0-23)。
  • getMilliseconds():返回毫秒(0-999)。
  • getMinutes():返回分钟(0-59)。
  • getSeconds():返回秒(0-59)。
  • getTimezoneOffset():返回当前时间与UTC的时区差异,以分钟表示,返回结果考虑到了夏令时因素。

# set类方法

Date对象提供了一系列 set 方法,用来设置实例对象的各个方面。

  • setDate(date):设置实例对象对应的每个月的几号(1-31),返回改变后毫秒时间戳。
  • setYear(year): 设置距离1900年的年数。
  • setFullYear(year [, month, date]):设置四位年份。
  • setHours(hour [, min, sec, ms]):设置小时(0-23)。
  • setMilliseconds():设置毫秒(0-999)。
  • setMinutes(min [, sec, ms]):设置分钟(0-59)。
  • setMonth(month [, date]):设置月份(0-11)。
  • setSeconds(sec [, ms]):设置秒(0-59)。
  • setTime(milliseconds):设置毫秒时间戳。

二、Math

Math是JavaScript的内置对象,提供一系列数学常数和数学方法。该对象不是构造函数,不能生成实例,所有的属性和方法都必须在Math对象上调用。

new Math()
// TypeError: object is not a function

上面代码表示,Math 不能当作构造函数用。

1. 属性

Math 对象提供以下一些只读的数学常数。(了解)

属性名描述
Math.E欧拉常数,也是自然对数的底数, 约等于 2.718
Math.LN22的自然对数, 约等于0.693
Math.LN1010的自然对数, 约等于 2.303
Math.LOG2E以2为底E的对数, 约等于 1.443
Math.LOG10E以10为底E的对数, 约等于 0.434
Math.PI圆周率,一个圆的周长和直径之比,约等于 3.14159 *
Math.SQRT1_21/2的平方根, 约等于 0.707
Math.SQRT22的平方根,约等于 1.414

2. 方法 *

属性名描述
Math.abs(x)返回x的绝对值
Math.ceil(x)返回x向上取整后的值
Math.floor(x)返回x向下取整后的值
Math.pow(x,y)返回x的y次幂
Math.sqrt(x)返回x的平方根
Math.random()返回0到1之间的伪随机数
Math.round(x)返回四舍五入后的整数
Math.max(...nums)最大值
Math.min(...nums)最小值

3. 随机数封装 *

任意范围的随机数(包含小数)生成函数如下:

// 100 ~ 200 的随机数
Math.random() * 100 + 100
// 函数式封装
function randomDecimals(min, max) {
  	// 异常处理
    if (min == undefined || max == undefined || isNaN(min) || isNaN(max)) {
        return -1;
    }else {
        return Math.random() * (max - min) + min;
    }
}

任意范围的随机整数生成函数如下:

// 100 ~ 200 的随机数
Math.floor(Math.random() * 101 + 100);
// 函数式封装
function randomInteger(min, max) {
    if (min == undefined || max == undefined || isNaN(min) || isNaN(max)) {
        return -1;
    }else {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }
}

返回随机字符的例子如下。

function random_char(length) {
    var bStr = '';
    bStr += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    bStr += 'abcdefghijklmnopqrstuvwxyz';
    bStr += '0123456789';

    var rStr = '';
    for (var i = 0; i < length; ++i) {
        var index = Math.floor(Math.random() * bStr.length);
        rStr += bStr.slice(index, index + 1);
    }
    return rStr;
}
random_char(6) // "NdQKOr"

上面代码中,random_char 函数接受一个整数作为参数,返回变量bStr内的随机字符所组成的指定长度的字符串。

三、JSON *

JSON 是一种语法,用来序列化对象、数组、数值、字符串、布尔值和 null 。它基于 JavaScript 语法,但与之不同:JavaScript不是JSON,JSON也不是JavaScript。JSON呈现形式如下:

{"name":"木子李", "age":31, "major":"WEB前端", "tags": ["老司机", "实力唱将"]}

提示:

  1. JSON 可以看做是严格模式下的对象,key值必须加上双引号。
  2. JSON 最外层通常是一个数组或对象

1. API

1.1. JSON.stringify()

1.1.1. 基础语法

将对象转换为 JSON 字符串,语法形式如下:

JSON.stringify(value[, replacer[, space]])

参数解读:

  • value:将要序列化成 一个 JSON 字符串的值。
  • replacer
    • 如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;
    • 如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;
    • 如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。
  • space
    • 指定缩进用的空白字符串,用于美化输出(pretty-print);
    • 如果参数是个数字,它代表有多少的空格;上限为10
    • 该值若小于1,则意味着没有空格;
    • 如果该参数为字符串(当字符串长度超过10个字母,取其前10个字母),该字符串将被作为空格;
    • 如果该参数没有提供(或者为 null),将没有空格。

返回值:一个标识给定值的 JSON 字符串

异常:

  • 当在循环引用时会抛出异常 TypeError ("cyclic object value")(循环对象值)
  • 当尝试去转换 BigInt 类型的值会抛出TypeError ("BigInt value can't be serialized in JSON")(BigInt值不能JSON序列化).

1.1.2. 基本使用

注意:

1)JSON.stringify 可以转换对象或者值(平常用的更多的是转换对象);

2)可以指定 replacer 为函数选择性的地替换;

3)也可以指定 replacer 为数组,可转换指定的属性;

// 1. 转换对象
console.log(JSON.stringify({ name: '耀哥', job: '前端工程师' })); // '{"name":"耀哥","job":"前端工程师"}'

// 2. 转换普通值
console.log(JSON.stringify('耀哥')); // "耀哥"
console.log(JSON.stringify(1)); // "1"
console.log(JSON.stringify(true)); // "true"
console.log(JSON.stringify(null)); // "null"

// 3. 指定replacer函数
console.log(
  JSON.stringify({ name: '耀哥', job: '前端工程师', age: 30 }, (key, value) => {
    return typeof value === 'number' ? undefined : value;
  })
);
// '{"name":"耀哥","job":"前端工程师"}'

// 4. 指定数组
console.log(JSON.stringify({ name: '耀哥', job: '前端工程师', age: 30 }, [ 'name' ])) // '{"name":"耀哥"}'

// 5. 指定space(美化输出)
console.log(JSON.stringify({ name: '耀哥', job: '前端工程师', age: 30 }))
// '{"name":"耀哥","job":"前端工程师"}'
console.log(JSON.stringify({ name: '耀哥', job: '前端工程师', age: 30 }, null , 2))
/*
{
  "name": "耀哥",
  "job": "前端工程师",
  "age": 30
}
*/

1.1.3. 九大特性

以前仅仅是使用了这个方法,却没有详细了解他的转换规则,居然有9个之多。

1)特性一

  • undefined任意的函数 以及 symbol值,出现在 非数组对象 的属性值中时在序列化过程中会被忽略

  • undefined任意的函数 以及 symbol值,出现在 数组 中时会被转换成 null

  • undefined任意的函数 以及 symbol值,被 单独转换 时,会返回 undefined

// 1. 对象中存在这三种值会被忽略
console.log(
  JSON.stringify({
    name: '耀哥',
    job: '前端工程师',
    // 函数会被忽略
    showName() {
      console.log('耀哥');
    },
    // undefined会被忽略
    age: undefined,
    // Symbol会被忽略
    symbolName: Symbol('耀哥'),
  })
);
// '{"name":"耀哥","job":"前端工程师"}'

// 2. 数组中存在着三种值会被转化为null
console.log(
  JSON.stringify([
    '耀哥',
    '前端工程师',
    // 函数会被转化为null
    function showName() {
      console.log('耀哥');
    },
    //undefined会被转化为null
    undefined,
    //Symbol会被转化为null
    Symbol('耀哥'),
  ])
);
// '["耀哥","前端工程师",null,null,null]'

// 3.单独转换会返回undefined
console.log(
  JSON.stringify(function showName() {
    console.log('耀哥');
  })
); // undefined
console.log(JSON.stringify(undefined)); // undefined
console.log(JSON.stringify(Symbol('耀哥'))); // undefined

2)特性二

布尔值数字字符串的包装对象在序列化过程中会自动转换成对应的原始值。

console.log(JSON.stringify([new Number(1), new String("中国成都"), new Boolean(false)]))
// '[1,"中国成都",false]'

3)特性三

所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。

console.log(JSON.stringify({ name: Symbol('耀哥') }));
// '{}'

console.log(
  JSON.stringify({ [Symbol('称呼')]: '耀哥' }, (key, value) => {
    if (typeof key === 'symbol') {
      return value;
    }
  })
);
// undefined

4)特性四

NaNInfinity 格式的数值及 null 都会被当做 null

console.log(
  JSON.stringify({
    age: NaN,
    num: Infinity,
    name: null,
  })
);
// '{"age":null,"num":null,"name":null}'

5)特性五

转换值如果有 toJSON() 方法,该方法定义什么值将被序列化。

const toJSONObj = {
  name: '耀哥',
  toJSON() {
    return 'JSON.stringify';
  },
};

console.log(JSON.stringify(toJSONObj));
// "JSON.stringify"

6)特性六

Date 日期调用了 toJSON() 将其转换为了 string 字符串(同 Date.toISOString() ),因此会被当做字符串处理。

const d = new Date()

console.log(d.toJSON()) // 2021-12-20T02:36:12.099Z
console.log(JSON.stringify(d)) // "2021-12-20T02:36:12.099Z"

7)特性七

对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。

let cyclicObj = { name: '耀哥' }
cyclicObj.obj = cyclicObj
console.log(JSON.stringify(cyclicObj))

// TypeError: Converting circular structure to JSON

8)特性八

其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性

let enumerableObj = {};
Object.defineProperties(enumerableObj, {
  name: {
    value: '耀哥',
    enumerable: true,
  },
  job: {
    value: '前端工程师',
    enumerable: false,
  },
});

console.log(JSON.stringify(enumerableObj));
// '{"name":"耀哥"}'

9)特性九

当尝试去转换 BigInt 类型的值会抛出错误、

const alsoHuge = BigInt(9007199254740991)

console.log(JSON.stringify(alsoHuge))
// TypeError: Do not know how to serialize a BigInt

1.2. JSON.parse()

将JSON字符串转换为对象,语法形式如下:

JSON.parse(text[, reviver])

代码示例:

var json = '{"name":"木子李","age":31,"major":"WEB前端","tags":["老司机","实力唱将"]}';
JSON.parse(json);

// { name: '木子李', age: 31, major: 'WEB前端', tags: [ '老司机', '实力唱将' ] }

2. 校验

jsonlint.com/

通过校验工具,可以检测JSON语法是否正确。