JavaScript学习04(标准对象)

标准对象

在JavaScript的世界里,一切都是对象。

但是某些对象还是和其他对象不太一样。为了区分对象的类型,我们用 typeof 操作符获取对象的类型,它总是返回一个字符串:

typeof 123; // 'number'
typeof NaN; // 'number'
typeof 'str'; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof Math.abs; // 'function'
typeof null; // 'object'
typeof []; // 'object'
typeof {}; // 'object'

Date

在JavaScript中, Date 对象用来表示日期和时间。

要获取系统当前时间,用:

var 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 对象表示的时间总是按浏览器所在时区显示的,不过我们既可以显示本地时间,也可以显示调整后的UTC时间:

var 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小时

那么在JavaScript中如何进行时区转换呢?实际上,只要我们传递的是一个 number 类型的时间戳,我们就不用关心时区转换。任何浏览器都可以把一个时间戳正确转换为本地时间。

时间戳是个什么?

时间戳是一个自增的整数,它表示从1970年1月1日零时整的GMT时区开始的那一刻,到现在的毫秒数。假设浏览器所在电脑的时间是准确的,那么世界上无论哪个时区的电脑,它们此刻产生的时间戳数字都是一样的,所以,时间戳可以精确地表示一个时刻,并且与时区无关。

所以,我们只需要传递时间戳,或者把时间戳从数据库里读出来,再让JavaScript自动转换为当地时间就可以了。

要获取当前时间戳,可以用:

if (Date.now) {
  console.log(Date.now()); // 老版本IE没有now()方法
} else {
  console.log(new Date().getTime());
}

面向对象编程

JavaScript的面向对象编程和大多数其他语言如Java、C#的面向对象编程都不太一样。如果你熟悉Java或C#,你一定明白面向对象的两个基本概念:

  • 类:类是对象的类型模板,例如,定义 Student 类来表示学生,类本身是一种类型,
    Student 表示学生类型,但不表示任何具体的某个学生;
  • 实例:实例是根据类创建的对象,例如,根据 Student 类可以创建出 xiaoming
    xiaohongxiaojun 等多个实例,每个实例表示一个具体的学生,他们全都属于
    Student 类型。

所以,类和实例是大多数面向对象编程语言的基本概念。

不过,在JavaScript中,这个概念需要改一改。JavaScript不区分类和实例的概念,而是通过原型(prototype)来实现面向对象编程。

原型是指当我们想要创建 xiaoming 这个具体的学生时,我们并没有一个 Student 类型可用。那怎么办?恰好有这么一个现成的对象:

var robot = {
  name: 'Robot',
  height: 1.6,
  run: function () {
    console.log(this.name + ' is running...');
 }
};

这个robot对象有名字,有身高,还会跑,有点像小明,干脆就根据它来“创建”小明得了!
于是我们把它改名为 Student ,然后创建出 xiaoming

var Student = {
  name: 'Robot',
  height: 1.2,
  run: function () {
    console.log(this.name + ' is running...');
 }
};

var xiaoming = {
  name: '小明'
};

xiaoming.__proto__ = Student;

注意最后一行代码把 xiaoming 的原型指向了对象 Student ,看上去xiaoming仿佛是从
Student 继承下来的:

xiaoming.name; // '小明'
xiaoming.run(); // 小明 is running...

xiaoming 有自己的name属性,但并没有定义 run() 方法。不过,由于小明是从 Student继承而来,只要 Student 有 run() 方法, xiaoming 也可以调用。

JavaScript的原型链和Java的Class区别就在,它没有“Class”的概念,所有对象都是实例,所谓继承关系不过是把一个对象的原型指向另一个对象而已。

class 继承

在上面的章节中我们看到了JavaScript的对象模型是基于原型实现的,特点是简单,缺点是理解起来比传统的类-实例模型要困难,最大的缺点是继承的实现需要编写大量代码,并且需要正确实现原型链。

新的关键字 class 从ES6开始正式被引入到JavaScript中。 class 的目的就是让定义类更简单。

如果用新的 class 关键字来编写 Student ,可以这样写:

class Student {
  constructor(name) {
    this.name = name;
 }
  hello() {
    alert('Hello, ' + this.name + '!');
 }
}

class 定义对象的另一个巨大的好处是继承更方便了。想一想我们从 Student 派生一个PrimaryStudent 需要编写的代码量。现在,原型继承的中间对象,原型对象的构造函数等等都不需要考虑了,直接通过 extends 来实现:

class PrimaryStudent extends Student {
  constructor(name, grade) {
    super(name); // 记得用super调用父类的构造方法!
    this.grade = grade;
 }
  myGrade() {
    alert('I am at grade ' + this.grade);
 }
}

上一篇:Javascript 设计模式系统讲解与应用


下一篇:JavaScript中this的指向问题