在 JavaScript 中,使用 new 关键字可以创建一个用户自定义对象类型的实例。这个过程包括以下步骤:
- 创建一个新的空对象。
- 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象)。
- 执行构造函数中的代码(给这个新对象添加属性)。
- 返回新对象。
构造函数
构造函数是一种特殊的函数,主要用来初始化对象。构造函数的命名通常首字母大写,以便与普通函数区分开来。
function Person(name, age) {
this.name = name;
this.age = age;
}
const person1 = new Person('Alice', 25);
console.log(person1.name); // 输出 "Alice"
console.log(person1.age); // 输出 25构造函数的注意事项
- 构造函数内部没有 return 语句时,默认返回的是 this 指向的对象。
- 如果构造函数有 return,并且返回值是一个原始类型,那么这个返回值会被忽略;如果返回值是一个引用类型,那么这个返回值会被作为构造函数的返回值。
// www.javascriptcn.com code example
function Constructor() {
this.value = 100;
return 10; // 返回原始类型
}
const instance = new Constructor();
console.log(instance.value); // 输出 100
function Constructor2() {
this.value = 100;
return { value: 200 }; // 返回引用类型
}
const instance2 = new Constructor2();
console.log(instance2.value); // 输出 undefined,实际返回 { value: 200 }类的定义
ES6 引入了 class 关键字,使得定义类变得更加直观和简单。尽管类本质上是基于原型的继承,但它们提供了一种更接近于面向对象编程的语言风格。
定义类
// www.javascriptcn.com code example
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
const dog = new Animal('Dog');
dog.speak(); // 输出 "Dog makes a noise."类的方法
类的方法默认都是可枚举的,并且默认不是可配置的、不可写的。如果需要修改这些行为,可以通过 Object.defineProperty 方法进行设置。
// www.javascriptcn.com code example
class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} meows.`);
}
}
Object.defineProperty(Cat.prototype, 'speak', {
writable: false,
configurable: false
});
const cat = new Cat('Cat');
cat.speak(); // 输出 "Cat meows."
// 尝试重新定义方法,会报错
Cat.prototype.speak = function() {
console.log('New sound.');
};静态方法
静态方法是属于类本身而不是类的实例的方法。它们不能通过实例调用,只能通过类名调用。
// www.javascriptcn.com code example
class Bird {
constructor(name) {
this.name = name;
}
static fly() {
console.log('Bird is flying.');
}
}
const sparrow = new Bird('Sparrow');
Bird.fly(); // 输出 "Bird is flying."
sparrow.fly(); // 报错:sparrow.fly is not a function继承
类可以通过 extends 关键字实现继承,从而复用父类的功能。
// www.javascriptcn.com code example
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类的构造函数
this.breed = breed;
}
bark() {
console.log(`${this.name} barks.`);
}
}
const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak(); // 输出 "Buddy makes a noise."
myDog.bark(); // 输出 "Buddy barks."覆盖方法
子类可以覆盖父类的方法。
// www.javascriptcn.com code example
class Parrot extends Animal {
constructor(name, color) {
super(name);
this.color = color;
}
speak() {
console.log(`${this.name} squawks.`);
}
}
const parrot = new Parrot('Polly', 'Green');
parrot.speak(); // 输出 "Polly squawks."super 关键字
super 关键字用于调用父类的方法。在子类构造函数中,必须先调用 super(),然后才能使用 this 关键字。
// www.javascriptcn.com code example
class Duck extends Animal {
constructor(name, color) {
super(name);
this.color = color;
}
quack() {
console.log(`${this.name} quacks.`);
}
speak() {
super.speak(); // 调用父类的 speak 方法
console.log(`and ${this.name} quacks.`);
}
}
const duck = new Duck('Donald', 'Yellow');
duck.speak(); // 输出 "Donald makes a noise." 和 "and Donald quacks."总结
本章介绍了如何使用 new 关键字创建类实例,以及如何定义和使用类、继承和静态方法等。理解这些概念对于掌握现代 JavaScript 编程至关重要。在接下来的内容中,我们将继续深入探讨其他相关主题。