constructor and new
Published by powerfulyang on Oct 6, 2022
构造函数
构造函数在技术上是常规函数。不过有两个约定:
- 它们的命名以大写字母开头。
- 它们只能由 "new" 操作符来执行。
1function User(name) {
2 this.name = name;
3 this.isAdmin = false;
4}
5
6let user = new User("Jack");
7
8alert(user.name); // Jack
9alert(user.isAdmin); // false
当一个函数被使用 new
操作符执行时,它按照以下步骤:
- 一个新的空对象被创建并分配给
this
。 - 函数体执行。通常它会修改
this
,为其添加新的属性。 - 返回
this
的值。
构造器模式测试:new.target
在一个函数内部,我们可以使用 new.target
属性来检查它是否被使用 new
进行调用了。
对于常规调用,它为 undefined,对于使用 new
的调用,则等于该函数:
1function User() {
2 alert(new.target);
3}
4
5// 不带 "new":
6User(); // undefined
7
8// 带 "new":
9new User(); // function User { ... }
它可以被用在函数内部,来判断该函数是被通过 new
调用的“构造器模式”,还是没被通过 new
调用的“常规模式”。
我们也可以让 new
调用和常规调用做相同的工作,像这样:
1function User(name) {
2 if (!new.target) { // 如果你没有通过 new 运行我
3 return new User(name); // ……我会给你添加 new
4 }
5
6 this.name = name;
7}
8
9let john = User("John"); // 将调用重定向到新用户
10alert(john.name); // John
new 操作符做了什么
- 在内存中创建一个新对象。
- 将新对象内部的 __proto__ 赋值为构造函数的 prototype 属性。
- 将构造函数内部的 this 被赋值为新对象(即 this 指向新对象)。
- 执行构造函数内部的代码(给新对象添加属性)。
- 如果构造函数返回非空对象,则返回该对象。否则返回 this。
new 操作符的模拟实现
1function fakeNew() {
2 // 创建新对象
3 var obj = Object.create(null);
4 var Constructor = [].shift.call(arguments);
5 // 将对象的 __proto__ 赋值为构造函数的 prototype 属性
6 obj.__proto__ = Constructor.prototype;
7 // 将构造函数内部的 this 赋值为新对象
8 var ret = Constructor.apply(obj, arguments);
9 // 返回新对象
10 return typeof ret === "object" && ret !== null ? ret : obj;
11}
12
13function Group(name, member) {
14 this.name = name;
15 this.member = member;
16}
17
18var group = fakeNew(Group, "hzfe", 17);