CodeAshen's blog CodeAshen's blog
首页
  • Spring Framework

    • 《剖析Spring5核心原理》
    • 《Spring源码轻松学》
  • Spring Boot

    • Spring Boot 2.0深度实践
  • Spring Cloud

    • Spring Cloud
    • Spring Cloud Alibaba
  • RabbitMQ
  • RocketMQ
  • Kafka
  • MySQL8.0详解
  • Redis从入门到高可用
  • Elastic Stack
  • 操作系统
  • 计算机网络
  • 数据结构与算法
  • 云原生
  • Devops
  • 前端
  • 实用工具
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
  • Reference
GitHub (opens new window)

CodeAshen

后端界的小学生
首页
  • Spring Framework

    • 《剖析Spring5核心原理》
    • 《Spring源码轻松学》
  • Spring Boot

    • Spring Boot 2.0深度实践
  • Spring Cloud

    • Spring Cloud
    • Spring Cloud Alibaba
  • RabbitMQ
  • RocketMQ
  • Kafka
  • MySQL8.0详解
  • Redis从入门到高可用
  • Elastic Stack
  • 操作系统
  • 计算机网络
  • 数据结构与算法
  • 云原生
  • Devops
  • 前端
  • 实用工具
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
  • Reference
GitHub (opens new window)
  • CSS3浮动定位与背景样式

  • CSS动画

  • JS基础语法与表达式

  • 流程控制语句与数组

  • JS函数与DOM

  • 面向对象

    • 01-面向对象
      • 对象的属性
      • 对象的方法
      • 对象的遍历
      • 对象的深浅克隆
      • 函数中的上下文
      • 上下文规则
      • call 和 apply
      • 对象上下文规则总结
      • 用 new 操作符调用函数
      • 构造函数
      • 类和实例
      • prototype 属性
      • 原型链查找
      • 在 prototype 上添加方法
      • 原型链的终点
      • 继承
      • 包装类
      • Math 对象
      • Date 对象
    • 02-继承与内置构造函数
  • 正则表达式

  • ES6基础入门

  • ES6语法扩展

  • Promise与Class

  • Module与Babel

  • 前端
  • 面向对象
CodeAshen
2023-02-10
目录

01-面向对象

# 认识对象

# 对象的属性

对象(object)是“键值对”的集合,表示属性和值的映射关系。

如果对象的属性键名不符合 JS 标识符命名规范,则这个键名必须用引号包裹。

var xiaoming = {
    name: '小明',  // 符合JS命名规范的key可以省略引号
    age: 12,
    sex: '男',
    hobbys: ['足球', '游泳', '编程'],
    'favorite-book': '舒克和贝塔'  // 不符合JS命名规范的key,必须用引号包裹
};
1
2
3
4
5
6
7

(1) 属性的访问

①点语法;②方括号。

可以用“点语法”访问对象中指定键的值,如 xiaoming.name;如果属性名不符合 JS 标识符命名规范,则必须用方括号的写法来访问,如 xiaoming['favorite-book']。

(2) 属性的更改

直接使用赋值运算符重新对某属性赋值即可更改属性

var obj = { a: 10 };
obj.a = 30;
obj.a++;
1
2
3

(3) 属性的创建

如果对象本身没有某个属性值,则用点语法赋值时,这个属性会被创建出来

var obj = { a: 10 };
obj.b = 40;
1
2

(4) 属性的删除

使用 delete 操作符删除对象的属性。

var obj = {
    a: 1,
    b: 2
};
delete obj.a;
1
2
3
4
5

# 对象的方法

如果某个属性值是函数,则它也被称为对象的**“方法”**。方法也是函数,只不过方法是对象的“函数属性”,它需要用对象打点调用。

var xiaoming = {
    name: '小明',
    age: 12,
    sex: '男',
    hobbys: ['足球', '游泳', '编程'],
    'favorite-book': '舒克和贝塔',
    // 对象的方法
    sayHello: function () {
        console.log('你好,我的小明');
    }
};

xiaoming.sayHello();  // 调用对象的方法
1
2
3
4
5
6
7
8
9
10
11
12
13

# 对象的遍历

和遍历数组类似,对象也可以被遍历,遍历对象需要使用 for...in... 循环,使用 for...in... 循环可以遍历对象的每个键。在后续的ES6相关课程中,还会学习新的对象遍历的方式。

// 遍历对象的所有键
for (var k in obj) {
    console.log('属性' + k + '的值是' + obj[k]);
}
1
2
3
4

# 对象的深浅克隆

回顾之前提过的基本类型值和引用类型值。

image-20220719023432087

对象是用类型值,这意味着:

  • 不能用 var obj2 = obj1 这样的语法克隆一个对象;
  • 使用 = 或者 == 进行对象的比较时,比较的是它们是否为内存中的同一个对象,而不是比较值是否相同。

对象的浅克隆

复习什么是浅克隆:只克隆对象的“表层”,如果对象的某些属性值又是引用类型值,则不进一步克隆它们,只是传递它们的引用。

使用 for...in... 循环即可实现对象的浅克隆。

var obj1 = {
    a: 1,
    b: 2,
    c: [44, 55, 66]
};
var obj2 = {};

// for...in... 进行浅克隆
for (var k in obj1) {
    obj2[k] = obj1[k];
}

// 浅克隆后,obj1和obj2的c属性是内存中的同一个数组,并没有分开
obj1.c.push(77);
console.log(obj2['c']);  // [44, 55, 66, 77]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

对象的深克隆

复习什么是深克隆:克隆对象的全貌,不论对象的属性值是否又是引用类型值,都能将它们实现克隆。和数组的深克隆类似,对象的深克隆需要使用递归。

var obj1 = {
    a: 1,
    b: 2,
    c: [33, 44, {
        m: 55,
        n: 66,
        p: [77, 88]
    }]
};

// 深克隆
function deepClone(o) {
    // 数组也是对象,要先判断数组,再判断对象
    if (Arrays.isArray(o)) {  // 数组
        var result = [];
        for (var i = 0; i < o.length; i++) {
            result.push(o[i]);
        }
    } else if (typeof o == 'object') {
        var result = {};
        for (var k in o) {
            result[k] = deepClone(o[k]);
        }
    } else {
        var result = o;
    }
    return result;
}

var obj2 = deepClone(obj1);
console.log(obj1.c == obj2.c);  // false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 认识函数的上下文

# 函数中的上下文

函数中可以使用 this 关键字,它表示函数的上下文。

与中文中"这”类似,函数中的 this 具体指代什么必须通过调用函数时的“前言后语”来判断。

var xiaoming = {
    nickname: '小明',
    age: 12,
    sayHello: function () {
        // 使用this关键字获取本对象中的属性
        console.log('我是' + this.nickname + ',我' + this.age + '岁了');
    }
};

xiaoming.sayHello();  // 我是小明,我12岁了

// 将函数提取出来,单独存为变量
var sayHello = xiaoming.sayHello();
sayHello();    // 我是undefined,我undefined岁了
1
2
3
4
5
6
7
8
9
10
11
12
13
14

第一次函数调用输出了预期结果,因为函数中的 this 指代了 xiaoming 这个对象;第二次调用出现了预期之外的情况,因为此时 this 指代了 window 对象。

对象 xiaoming 没有改变过,函数也没有改变过,唯一不同的是函数的调用方式。所以有一个重要的结论:函数的上下文由函数的调用方式决定。同一个函数,用不同的形式调用它,则函数的上下文不同。

  • 情形1:对象打点调用函数,函数中的 this 指代这个打点的对象

    xiaoming.sayHello();
    
    1
  • 情形2:圆括号直接调用函数,函数中的 this 指代 window 对象

    var sayHello xiaoming.sayHello;
    sayHello();
    
    1
    2

函数的上下文(this关键字)跟函数在哪里定义没关系,由函数的调用方式决定。函数如果不调用,则不能确定函数的上下文。

# 上下文规则

既然函数上下文由函数调用方式决定,那么接下来就介绍函数上下问的一些规则,即不同的函数调用方式。

  • 规则1:对象打点调用它的方法函数,则函数的上下文是这个打点的对象。

    对象.方法();
    
    1
  • 规则2:圆括号直接调用函数,则函数的上下文是 window 对象

    函数();
    
    1
  • 规则3:数组(类数组对象)枚举出函数进行调用,上下文是这个数组(类数组对象)

    数组[下标]();
    
    1
  • 规则4:IIFE 中的函数,上下文是 window 对象

    (function() {
        
    })();
    
    1
    2
    3
  • 规则5:定时器、延时器调用函数,上下文是 window 对象

    setInterval(函数, 时间);
    setTimeout(函数, 时间);
    
    1
    2
  • 规则6:事件处理函数的上下文是绑定事件的 DOM 元素

    DOM元素.onclick = function () {
        
    };
    
    1
    2
    3

# call 和 apply

需求:由如下函数和对象,现在想用 sum 函数统计对象 xiaoming 的成绩总和。

function sum() {
    alert(this.chinese + this.math + this.english);
}

var xiaoming = {
    chinese: 80,
    math: 95,
    english: 93
};
1
2
3
4
5
6
7
8
9

根据上下文规则 1,可以将函数 sum 称为对象 xiaoming 的方法,然后使用 xiaoming.sum() 来调用函数即可实现需求。

xiaoming.sum = sum;
xiaoming.sum();
1
2

除此之外,还由更简单的方法,就是使用 call 和 apply。

call 和 apply 能指定函数的上下文,这样函数就会以指定的上下文执行。

函数.call(上下文);
函数.apply(上下文);
1
2

这样上述需求就可以写成这样:

// 以xiaoming为上下文,执行sum函数
sum.call(xiaoming);
sum.apply(xiaoming);  // 选其一
1
2
3

call 和 apply 的区别在于调用带有参数的函数时,传递参数的方式不同。call 要求用逗号罗列;apply 要求传递数组。

// 带参数的函数
function sum(b1, b2) {
    alert(this.c + this.m + this.e + b1 + b2);
}

// 指定上下文调用函数,并且传递参数
sum.call(xiaoming, 5, 3);     // call 要求用逗号罗列
sum.apply(xiaoming, [5, 3]);  // apply 要求传递数组
1
2
3
4
5
6
7
8

# 对象上下文规则总结

image-20220723223911358

# 构造函数

# 用 new 操作符调用函数

现在,我们学习一种新的函数调用方式:

new 函数()
1

你可能知道 new 操作符和“面向对象”息息相关,但是现在,我们先不探讨它的“面向对象”意义,而是先把用 new 调用函数的执行步聚和它上下文弄清楚。

JS 规定,使用 new 操作符调用函数会进行“四步走”:

  1. 函数体内会自动创建出一个空白对象;
  2. 函数的上下文(this)会指向这个对象;
  3. 函数体内的语句会执行;
  4. 函数会自动返回上下文对象,即使函数没有 return 语句。

下面结合一个示例来解释这四步:

function fun() {
    this.a = 3;
    this.b = 5;
}

var obj = new fun();
console.log(obj);     // {a: 3, b: 5}
1
2
3
4
5
6
7

示例中第 6 行使用 new 关键字调用了 fun 函数,其执行步骤如下:

  1. 再执行函数体前会创建一个空白对象 {};
  2. 函数 fun 的上下文指向创建出的空白对象 {},函数体内的 this 都指代这个对象;
  3. 执行函数体内语句,空白对象会被赋予属性,变成 {a: 3, b: 5};
  4. 最后会返回这个对象 {a: 3, b: 5},相当于自动补充了 return this。

至此,函数上下文规则又多了一条。

image-20220723225322874

# 构造函数

什么是构造函数?

  • 用 new 调用一个函数,这个函数就被称为“构造函数”,任何函数都可以是构造函数,只需要用 new 调用它。
  • 顾名思义,构造函数用来“构造新对象”,它内部的语句将为新对象添加若干属性和方法,完成对象的初始化。
  • 构造函数必须用 new 关键字调用,否则不能正常工作,正因如此,开发者约定构造函数命名时首字母要大写。
function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.sayHello = function () {
        console.log('我是' + this.name);
    }
}

var xiaoming = new People('小明', 12, '男');
var xiaohong = new People('小红', 10, '女');
1
2
3
4
5
6
7
8
9
10
11

题目:一个函数名称首字母大写了,它就是构造函数。这句话是否正确?

答案:错误。一定要记住:一个函数是不是构造函数,要看它是否用 new 关键字调用,而至于名称首字母大写,完全是开发者的习惯约定。

如果不用 new 关键字调用函数,那就是不同的函数调用。

People('小明', 12, '男');
People('小红', 10, '女');

console.log(window.name);   // 小红 
1
2
3
4

如果按照以上方式调用 People 函数,则不是构造函数,函数中的 this 指向 window 对象,函数体会为 window 对象设置属性,并且后一次调用会覆盖前一次调用设置上的属性。

# 类和实例

类好比是“蓝图”,类只描述对象会拥有哪些属性和方法但是并不具体指明属性的值;实例是具体的对象。

Java、C++ 等是"面向对象”(object-oriented)语言,JavaScript 是“基于对象”(object-based)语言。

JavaScript 中的构造函数可以类比于 OO 语言中的“类”,写法的确类似,但和真正 OO 语言还是有本质不同,在后续章节还将看见 JS 和其他 OO 语言完全不同的、特有的原型特性。

image-20220723235114482

# 原型和原型链

# prototype 属性

任何函数都有 prototype 属性,prototype 是英语“原型”的意思。

prototype 属性值是个对象,它默认拥有 constructor 属性指回函数。

image-20220723235322863

function sum(a, b) {
    return a + b;
}

console.log(sum.prototype);
console.log(typeof sum.prototype);  // object
console.log(sum.prototype.constructor === sum);  // true
1
2
3
4
5
6
7

普通函数来说的 prototype 属性没有任何用处,而构造函数的 prototype 属性非常有用。 构造函数的 prototype 属性是它的实例的原型。

image-20220724003201376

function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}

var xiaoming = new People('小明', 12, '男');
console.log(xiaoming.__proto__ === People.prototype);  // true
1
2
3
4
5
6
7
8

# 原型链查找

JavaScript 规定:实例可以打点访问它的原型的属性和方法,这被称为“原型链查找”。

function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}

// 在构造函数的 prototype 上添加 nationality 属性
People.prototype.nationality = '中国';

var xiaoming = new People('小明', 12, '男');
// 实例可以打点访问原型的属性和方法
console.log(xiaoming.nationality);   // 中国
1
2
3
4
5
6
7
8
9
10
11
12

image-20220724004113641

通过构造函数,为对象 xiaoming 添加的 name、age 和 sex 属性,把 nationality 属性直接添加到了 People.prototype 对象上,此时对象 xiaoming 可以通过打点直接原形是属性和方法的。

通过 xiaoming.nationality 访问属性时,JS 发现 xiaoming 对象中没有该属性,就会尝试去寻找它的原型,这就是原型链查找。

**如果对象中本身已经有要访问的属性或方法,就不会在原型中查找了。**如下例:

var tom = new People('Tom', 15, '男');
tom.nationality = '美国';
console.log(tom.nationality);   // 美国
1
2
3

image-20220724004235284

本节最后介绍 hasOwnProperty 方法和 in 运算符。

hasOwnProperty 方法可以检查对象是否真正“自己拥有”某属性或者方法。

xiaoming.hasownProperty('name');         // true
xiaoming.hasOwnProperty('age')           // true
xiaoming.hasownProperty('sex');          // true
xiaoming.hasOwnProperty('nationality');  // false
1
2
3
4

in 运算符只能检查某个属性或方法是否可以被对象访问,不能检查是否是自己的属性或方法。

'name' in xiaoming         // true
'age' in xiaoming          // true
'sex' in xiaoming          // true
'nationality' in xiaoming  // true
1
2
3
4

# 在 prototype 上添加方法

在之前的课程中,我们把方法都是直接添加到实例身上,其实这样是不规范的。

function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.sayHello = function () {
        console.log('我是' + this.name);
    }
}
1
2
3
4
5
6
7
8

这样作的后果是,使用构造函数创建出的多个对象中都有 sayHello 方法,并且它们在内存中是不同的函数。

image-20220724010015123

var xiaoming = new People('小明', 12, '男');
var xiaohong = new People('小红', 10, '女');

console.log(xiaoming.sayHello === xiaohong.sayHello);  // false
1
2
3
4

把方法直接添加到实例身上的缺点:每个实例和每个实例的方法函数都是内存中不同的函数,造成了内存的浪费。

解决办法:将方法写到 prototype 上。

image-20220724010041513

function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}

People.prototype.sayHello = function () {
    console.log('我是' + this.name);
};
1
2
3
4
5
6
7
8
9

# 原型链的终点

我们之前创建的对象及其原型中,并没有定义 hasOwnProperty 等方法,但是所有的对象都可以调用这个方法,这是为什么呢?

image-20220724010502391

对象 xiaoming 的原型是 People.prototype,它也是一个对象,它也有自己的原型。JS 中内置了 Object 构造函数,它的 Object.prototype 属性就是就是 People.prototype 的原型,也是原型链的终点。

我们之前调用的诸如 hasOwnProperty 方法,都是通过原型链调用的 Object.prototype 中的方法。

var xiaoming = new People('小明', 12, '男');

console.log(xiaoming.__proto__.__proto__ === Object.prototype);  // true
console.log(Object.prototype.__proto__);  // null
1
2
3
4

关于数组的原型:

image-20220724011725158

var arr = [1, 2, 3];

console.log(arr.__proto__ === Array.prototype);  // true
console.log(arr.__proto__.__proto__ === Object.prototype);  // true
1
2
3
4

# 继承

image-20220724012354134

People 类和 Student 类的关系:

  • People 类拥有的属性和方法 Student 类都有,Student 类还扩展了一些属性和方法;
  • Student 是一种 People,两类之间是 “is a kind of” 关系;
  • 这就是继承关系:Student 类继承自 People 类。

继承描述了两个类之间的 "is a kind of" 关系,比如学生“是一种”人,所以人类和学生类之间就构成继承关系。

People 是“父类”(或“超类”、“基类”);Student 是“子类”(或“派生类”),子类丰富了父类,让类描述得更具体、更细化。

JavaScript 中如何实现继承

实现继承的关键在于:子类必须拥有父类的全部属性和方法,同时子类还应该能定义自己特有的属性和方法。

使用 JavaScript 特有的原型链特性来实现继承,是普遍的做法。在今后学习 ES6 时,将介绍新的实现继承的方法。

image-20220724012725868

// 父类:People类
function People(name, age, sex) {
    // this.arr = [33, 44, 55];
    this.name = name;
    this.age = age;
    this.sex = sex;
}
People.prototype.sayHello = function () {
    console.log('你好,我是' + this.name + '我今年' + this.age + '岁了');
};
People.prototype.sleep = function () {
    console.log(this.name + '正在睡觉');
};

// 子类:Student类
function Student(name, age, sex, school, sid) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.school = school;
    this.sid = sid;
}

// 实现继承的非常重要的语句。让子类的prototype指向父类的一个实例。
Student.prototype = new People();
// 子类中的新方法
Student.prototype.exam = function () {
    console.log(this.name + '正在考试');
};
Student.prototype.study = function () {
    console.log(this.name + '正在学习');
};
// 子类可以更改父类的方法,术语叫做override“改写”、“重写”
Student.prototype.sayHello = function () {
    console.log('敬礼!您好,我是' + this.name + ',我是' + this.school + '的学生,我' + this.age + '岁了');
};


// 测试
var hanmeimei = new Student('韩梅梅', 9, '女', '第二小学', 100556);
hanmeimei.sayHello();
hanmeimei.sleep();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# JS 的内置对象

# 包装类

Number()、String() 和 Boolean() 分别是数字、字符串、布尔值的**“包装类”**。

很多编程语言都有“包装类”的设计,包装类的目的就是为了让基本类型值可以从它们的构造函数的 prototype 上获得方法。

var a = new Number(123);
var b = new String('hello');
var c = new Boolean(true);
1
2
3

a、b、c 是基本类型值么?它们和普通的数字、字符串、布尔值有什么区别吗?

// console.log(3);
// console.log(typeof 3);

var o = new Number(3);
console.log(o);
console.log(typeof o);
console.log(5 + o);     // 8


var s = new String('abc');
console.log(s);
console.log(typeof s);
console.log(String.prototype.hasOwnProperty('slice'));
console.log(String.prototype.hasOwnProperty('substring'));
console.log(String.prototype.hasOwnProperty('substr'));

var b = new Boolean(true);
console.log(b);
console.log(typeof b);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

包装类总结:

  • Number()、String() 和 Boolean() 的实例都是 object 类型,它们的 PrimitiveValue 属性存储它们的本身值;
  • new 出来的基本类型值可以正常参与运算;
  • 包装类的目的就是为了让基本类型值可以从它们的构造函数的 prototype 上获得方法。

# Math 对象

幂和开方:Math.pow()、Math.sqrt()

向上取整和向下取整:Math.ceil()、Math.floor()

Math.round() 可以将一个数字四舍五入为整数

console.1og(Math.round(3.4));   //13
console.1og(Math.round(3.5));   //14
console.log(Math.round(3.98));  //14
console.log(Math.round(3.49));  //13
1
2
3
4

如何才能实现“四舍五入到小数点后某位”呢?

image-20220724020752353

// 对于小数 num 四舍五入,保留 n 位小数
function fun(num, n) {
    return Math.round(num * 100) / 100;
}
1
2
3
4

Math.max() 可以得到参数列表的最大值

Math.min() 可以得到参数列表的最小值

console.log(Math.max(6, 2, 9, 4));  // 9
console.log(Math.min(6, 2, 9, 4));  // 2
1
2

如何利用 Math.max() 求数组最大值?

Math.max() 要求参数必须是“罗列出来”,而不能是数组,还记得 apply 方法么?它可以指定函数的上下文,并且以数组的形式传入“零散值”当做函数的参数。

var arr = [3, 6, 9, 2];
var max Math.max.apply(null, arr);
console.log(max);   // 9

// 学习 ES6 之后,求数组最大值还可以
console.log(Math.max(...arr));
1
2
3
4
5
6

随机数 Math.random()

Math.random() 可以得到 0~1 之间的小数,为了得到 [a,b] 区间内的整数,可以使用这个公式:

parseInt(Math.random() * (b - a + 1)) + a
1

# Date 对象

创建 Date 对象

使用 new Date() 即可得到当前时间的日期对象,它是 object 类型值;

使用 new Date(2020, 11, 1) 即可得到指定日期的日期对象,注意第二个参数表示月份,从 0 开始算,11 表示 12 月;

也可以是 new Date('2020-12-01') 这样的写法。

// 得到当前时间的日期对象
var d1 = new Date();

// 得到6月1日日期对象
var d2 = new Date(2022, 5, 1);    // 不算时区,创建出来时间为 0:00
var d3 = new Date('2022-06-01');  // 算时区,东八区创建出来时间为 8:00

console.log(d1);  // Sun Jul 24 2022 15:25:28 GMT+0800 (中国标准时间)
console.log(d2);  // Wed Jun 01 2022 00:00:00 GMT+0800 (中国标准时间)
console.log(d3);  // Wed Jun 01 2022 08:00:00 GMT+0800 (中国标准时间)
1
2
3
4
5
6
7
8
9
10

日期中的常见方法

image-20220724022844864

时间戳

时间戳表示1970年1月1日零点整距离某时刻的毫秒数 通过getTime()方法或者Date.parse()函数可以将日期对象变 为时间戳 通过new Date(时间戳)的写法,可以将时间戳变为日期对象

var d = new Date();

// 日期转时间戳,单位:毫秒
var ts1 = d.getTime();    // 精确到毫秒
var ts2 = Date.parse(d);  // 单位毫秒,精确到秒,最后三位为000

console.log(ts1);  // 1658601332759
console.log(ts2);  // 1658601332000

// 时间戳转日期
var d1 = new Date(ts1);
1
2
3
4
5
6
7
8
9
10
11
编辑 (opens new window)
上次更新: 2023/06/04, 12:34:19
03-BOM基础
02-继承与内置构造函数

← 03-BOM基础 02-继承与内置构造函数→

最近更新
01
第01章-RabbitMQ导学
02-10
02
第02章-入门RabbitMQ核心概念
02-10
03
第03章-RabbitMQ高级特性
02-10
更多文章>
Theme by Vdoing | Copyright © 2020-2023 CodeAshen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式