摘要: 在本教程中,您将学习关于 JavaScript 构造函数以及如何使用 new
关键字创建对象。
JavaScript 构造函数简介
在 JavaScript 对象教程 中,您学习了如何使用对象字面量语法创建新对象。
例如,以下代码创建了一个新的 person
对象,它包含两个属性 firstName
和 lastName
let person = {
firstName: 'John',
lastName: 'Doe'
};
Code language: JavaScript (javascript)
在实践中,您经常需要创建许多类似于 person
对象的对象。
为此,您可以使用构造函数来定义自定义类型,并使用 new
运算符从该类型创建多个对象。
从技术上讲,构造函数是一个普通的 函数,遵循以下约定
- 构造函数的名称以大写字母开头,例如
Person
、Document
等。 - 构造函数只能使用
new
运算符调用。
请注意,ES6 引入了 class
关键字,允许您定义自定义类型。类只是构造函数的语法糖,并提供了一些增强功能。
以下示例定义了一个名为 Person
的构造函数
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Code language: JavaScript (javascript)
在本例中,Person
与普通函数相同,只是其名称以大写字母 P
开头。
要创建 Person
的新实例,可以使用 new
运算符
let person = new Person('John','Doe');
Code language: JavaScript (javascript)
基本上,new
运算符执行以下操作
- 创建一个新的空对象,并将其分配给
this
变量。 - 将参数
'John'
和'Doe'
分别分配给对象的firstName
和lastName
属性。 - 返回
this
值。
它在功能上等效于以下代码
function Person(firstName, lastName) {
// this = {};
// add properties to this
this.firstName = firstName;
this.lastName = lastName;
// return this;
}
Code language: JavaScript (javascript)
因此,以下语句
let person = new Person('John','Doe');
Code language: JavaScript (javascript)
… 返回的结果与以下语句相同
let person = {
firstName: 'John',
lastName: 'Doe'
};
Code language: JavaScript (javascript)
但是,构造函数 Person
允许您创建多个类似的对象。例如
let person1 = new Person('Jane','Doe')
let person2 = new Person('James','Smith')
Code language: JavaScript (javascript)
向 JavaScript 构造函数添加方法
对象可能包含用于操作其数据的方法。要向通过构造函数创建的对象添加方法,可以使用 this
关键字。例如
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function () {
return this.firstName + " " + this.lastName;
};
}
Code language: JavaScript (javascript)
现在,您可以创建一个新的 Person
对象并调用 getFullName()
方法
let person = new Person("John", "Doe");
console.log(person.getFullName());
Code language: JavaScript (javascript)
输出
John Doe
构造函数的问题在于,当您创建 Person
的多个实例时,this.getFullName()
会在每个实例中重复,这在内存效率方面并不理想。
为了解决这个问题,您可以使用 原型,以便自定义类型的所有实例都可以共享相同的方法。
从构造函数返回
通常,构造函数会隐式返回 this
,该值设置为新创建的对象。但如果它包含 return
语句,则存在以下规则
- 如果使用对象调用
return
,则构造函数返回该对象,而不是this
。 - 如果使用对象以外的值调用
return
,则会忽略它。
在没有 new
关键字的情况下调用构造函数
从技术上讲,您可以像普通函数一样调用构造函数,而不使用 new
关键字,如下所示
let person = Person('John','Doe');
Code language: JavaScript (javascript)
在这种情况下,Person
只是像普通函数一样执行。因此,Person
函数内部的 this
不会绑定到 person
变量,而是绑定到 全局对象。
如果您尝试访问 firstName
或 lastName
属性,则会收到错误
console.log(person.firstName);
Code language: CSS (css)
错误
TypeError: Cannot read property 'firstName' of undefined
Code language: JavaScript (javascript)
同样,您也无法访问 getFullName()
方法,因为它绑定到全局对象。
person.getFullName();
Code language: CSS (css)
错误
TypeError: Cannot read property 'getFullName' of undefined
Code language: JavaScript (javascript)
为了防止在没有 new
关键字的情况下调用构造函数,ES6 引入了 new.target
属性。
如果使用 new
关键字调用构造函数,则 new.target
返回函数的引用。否则,它返回 undefined
。
以下代码向 Person
函数添加了一个语句,用于将 new.target
显示到控制台
function Person(firstName, lastName) {
console.log(new.target);
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function () {
return this.firstName + " " + this.lastName;
};
}
Code language: JavaScript (javascript)
以下代码返回 undefined
,因为 Person
构造函数像普通函数一样被调用
let person = Person("John", "Doe");
Code language: JavaScript (javascript)
输出
undefined
Code language: JavaScript (javascript)
但是,以下代码返回 Person
函数的引用,因为它使用 new
关键字被调用
let person = new Person("John", "Doe");
Code language: JavaScript (javascript)
输出
[Function: Person]
Code language: JSON / JSON with Comments (json)
通过使用 new.target
,您可以强制构造函数的调用者使用 new
关键字。否则,您可以抛出错误,如下所示
function Person(firstName, lastName) {
if (!new.target) {
throw Error("Cannot be called without the new keyword");
}
this.firstName = firstName;
this.lastName = lastName;
}
Code language: JavaScript (javascript)
或者,您可以通过在构造函数的调用者没有使用 new
关键字的情况下创建一个新的 Person
对象,使语法更加灵活
function Person(firstName, lastName) {
if (!new.target) {
return new Person(firstName, lastName);
}
this.firstName = firstName;
this.lastName = lastName;
}
let person = Person("John", "Doe");
console.log(person.firstName);
Code language: JavaScript (javascript)
这种模式经常在 JavaScript 库和框架中使用,以使语法更加灵活。
总结
- JavaScript 构造函数是一个普通的函数,用于创建多个类似的对象。