1. 构造函数
JavaScript中的构造函数是一种特殊的函数,用于创建对象。构造函数的命名方式通常是首字母大写。
1.1 创建构造函数
创建构造函数的语法如下:
function Person(name, age) {
this.name = name;
this.age = age;
}
上面的代码中,我们定义了一个叫做Person的构造函数,它接收两个参数name和age,并将它们分别赋值给this.name和this.age。在JS中,用this来指代当前对象。
1.2 创建实例
要创建一个Person的实例,可以使用new关键字:
const john = new Person('John', 25);
console.log(john); // Person { name: 'John', age: 25 }
通过使用new关键字,我们可以实例化一个Person对象,并将其赋值给john变量。在这个例子中,我们将'John'作为name参数,25作为age参数传递给构造函数,这样就创建了一个Person对象,它的name属性为'John',age属性为25。
1.3 构造函数prototype
在JavaScript中,每个函数都有一个名为prototype的属性,它可以用来添加属性和方法到实例中。
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
}
john.greet(); // Hello, my name is John
在上面的代码中,我们向Person对象的prototype属性添加了一个greet方法。这个方法可以被所有通过该构造函数创建的对象调用。在这个例子中,我们通过john对象调用greet方法,它的输出是'Hello, my name is John'。
2. 原型
在JavaScript中,每个对象都有一个名为__proto__的属性,它指向对象的原型。原型的作用是共享属性和方法。
2.1 实例与原型
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
}
const john = new Person('John', 25);
console.log(john.__proto__); // { greet: ? }
john.greet(); // Hello, my name is John
在上面的代码中,我们使用构造函数Person创建了一个实例john。john的__proto__指向了Person的prototype对象,这意味着它可以从Person的原型中继承greet方法。当我们在john上调用greet方法时,它输出了'Hello, my name is John'。
2.2 原型链
在JavaScript中,每个对象都有一个原型。如果一个对象无法找到所需的属性或方法,它会在它的原型上查找,如果原型中也没有找到,它会继续查找原型的原型,直到找到或查找完整个原型链。
const obj = {};
console.log(obj.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
在上面的代码中,我们创建了一个空对象obj,并打印了它的原型。由于这是一个空对象,它的原型是Object.prototype。接下来,我们打印了Object.prototype的原型,它是null。这意味着Object.prototype是原型链的最终节点,它没有原型。
2.3 原型与构造函数
每个构造函数都有一个prototype属性,它指向构造函数创建的所有实例的原型。当一个对象被实例化时,它的原型会指向构造函数的prototype属性。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
}
const john = new Person('John', 25);
console.log(john.__proto__ === Person.prototype); // true
在上面的代码中,我们定义了Person构造函数,并将greet方法添加到Person.prototype中。接下来,我们创建了一个名为john的实例,并检查它的__proto__是否指向Person.prototype。
这种继承关系可以用以下图示表示:
2.4 原型继承
在JavaScript中,可以通过原型继承来创建子对象。子对象可以继承父对象的属性和方法。
function Animal(name) {
this.name = name;
}
Animal.prototype.sayName = function() {
console.log(`My name is ${this.name}`);
}
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log(`Woof, I'm a ${this.breed}`);
}
const fido = new Dog('Fido', 'Labrador Retriever');
fido.sayName(); // "My name is Fido"
fido.bark(); // "Woof, I'm a Labrador Retriever"
在上面的代码中,我们定义了两个构造函数,Animal和Dog。Animal构造函数接收一个name参数,并将它赋值给this.name。同时,Animal.prototype上有一个sayName方法用来输出这个名字。Dog构造函数扩展了Animal构造函数,它除了继承Animal的属性和方法之外,还添加了一个breed属性和一个bark方法,用来输出它的品种和一个狗吠声。 在创建Dog.prototype时,我们使用Object.create()方法来将Animal.prototype设置为新对象的原型。这意味着Dog.prototype可以继承Animal.prototype上的所有方法。最后,我们将Dog.prototype.constructor设置为Dog,以便我们可以正确识别它。
3. 总结
在JavaScript中,构造函数和原型是两个非常重要的概念。当我们创建一个实例时,它会继承构造函数的所有属性和方法,并且可以通过原型链访问到它的原型上的属性和方法。通过构造函数和原型,我们可以使用面向对象编程的概念来编写更具可维护性和可扩展性的代码。