六维教程

JavaScript 构造函数与 new

前面几篇创建对象一直用的是对象字面量,一个两个没问题,数量多了就繁琐了。假如一个网站有上千个用户,每个用户都有 name、age、email 这些属性,难道要手写一千遍 { name: '...', age: ... } 吗?构造函数就是用来解决这种批量创建对象的问题。

为什么需要构造函数

用字面量创建几个结构相同的对象,可以看到问题所在。

const user1 = {
  name: '张三',
  age: 18,
  email: 'zhangsan@example.com'
};

const user2 = {
  name: '李四',
  age: 20,
  email: 'lisi@example.com'
};

问题很明显,每写一个用户就要把属性名完整重复一遍。如果以后要加一个 phone 属性,得回头把所有对象都改一遍,很容易漏改或写错。我们想要的是一份”模板”,传入不同的数据,就能批量生成结构相同的对象。

构造函数是什么

构造函数本质上还是一个普通函数,只是有两条约定俗成的规矩。

  1. 函数名首字母大写,用来和普通函数区分。
  2. 函数内部用 this 给新对象添加属性。
function User(name, age) {
  this.name = name;
  this.age = age;
}

注意这个函数没有 return 任何东西,看起来只是往 this 上挂属性。单独调用 User('张三', 18) 没有意义,因为 this 不知道指向谁,它必须配合 new 使用。关于参数传递的细节可以回顾 JavaScript 函数参数

new 关键字做了什么

执行 new User('张三', 18) 时,JavaScript 在内部悄悄完成了三步。

  1. 创建一个新的空对象。
  2. 把这个新对象赋值给函数内部的 this,于是函数里的 this.name = name 都作用在这个新对象上。
  3. 把这个新对象作为结果返回出来。

也就是说,new 帮我们完成了”创建对象、绑定 this、返回对象”这三件事,构造函数里只需要专心往 this 上挂属性即可。this 的完整规则可以回顾 JavaScript this 指向基础

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

const user1 = new User('张三', 18);
console.log(user1.name); // 张三
console.log(user1.age);  // 18

const user2 = new User('李四', 20);
console.log(user2.name); // 李四

同一个构造函数可以 new 出任意多个结构相同的对象,批量创建的问题就解决了。传不同参数,得到不同数据、相同结构的实例。

实例是什么

用 new 出来的对象,称为这个构造函数的实例。user1 和 user2 都是 User 的实例,实例之间互不影响,改 user1 的 name 不会波及 user2。

判断一个对象是不是某个构造函数的实例,可以用 instanceof 运算符,结果为布尔值。

const user1 = new User('张三', 18);

console.log(user1 instanceof User);  // true
console.log(user1 instanceof Array); // false

给实例添加方法

构造函数里也可以挂方法,先看一种写法(下一篇会讲更推荐的写法)。

function User(name, age) {
  this.name = name;
  this.age = age;
  this.sayHi = function () {
    console.log('你好,我是 ' + this.name);
  };
}

const user1 = new User('张三', 18);
user1.sayHi(); // 你好,我是 张三

每个实例都带上了自己的 sayHi,调用时 this 指向调用它的实例。

小结

  • 构造函数是首字母大写的普通函数,内部用 this 给新对象添加属性。
  • new 负责三件事,创建空对象、把 this 指向新对象、返回新对象。
  • new 出来的对象叫实例,instanceof 可以判断实例属于哪个构造函数。
  • 构造函数解决批量创建结构相同对象的问题。
  • 构造函数的 prototype 属性和原型机制有关,下一篇专门讲。
上一篇
JavaScript Math 与 Date 内置对象
下一篇
JavaScript 原型是什么