下面是 JavaScript 实现继承的六种方式的详细攻略:
1. 原型链继承
原型链继承是 JavaScript 实现继承最常用的方式之一。通过将子类的原型指向父类的实例,从而实现对父类属性和方法的继承。具体代码实现如下:
// 父类
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function () {
console.log("My name is " + this.name + ".");
};
// 子类
function Student(name, grade) {
this.grade = grade;
}
Student.prototype = new Person();
// 实例化子类
let s1 = new Student("Tom", "3");
s1.sayName(); // 输出 "My name is Tom."
这里我们将子类的原型 Student.prototype
指向了父类的实例 new Person()
,这样子类的实例 s1
就可以直接访问父类 Person
的属性和方法了。
一个注意点是,子类自身定义的属性或方法会覆盖继承来的父类属性或方法,例如:
function Student(name, grade) {
this.grade = grade;
this.sayName = function () {
console.log("I am Student, my name is " + this.name + ".");
};
}
let s2 = new Student("Tony", "5");
s2.sayName(); // 输出 "I am Student, my name is Tony."
上面的 sayName
方法覆盖了父类 Person
的同名方法。
2. 借用构造函数
借用构造函数是在子类构造函数内部通过 call
或 apply
调用父类构造函数的方式实现继承。但是借用构造函数只能继承父类的属性,不能继承方法。具体代码实现如下:
// 父类
function Person(name) {
this.name = name;
this.sayName = function () {
console.log("My name is " + this.name + ".");
};
}
// 子类
function Student(name, grade) {
Person.call(this, name); // 借用父类的构造函数初始化属性
this.grade = grade;
}
// 实例化子类
let s3 = new Student("Jack", "2");
s3.sayName(); // 报错,父类的方法没有被继承
console.log(s3.name); // 输出 "Jack"
我们在子类的构造函数中通过 Person.call(this, name)
调用了父类 Person
的构造函数,从而实现对父类实例属性 name
的继承。但是由于没有继承父类的方法,所以调用 s3.sayName()
会报错。
3. 组合继承
组合继承是原型链继承和借用构造函数组合起来的方式。它通过原型链继承父类的方法和通过借用构造函数继承父类的属性两种方式结合来实现继承。具体代码实现如下:
// 父类
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function () {
console.log("My name is " + this.name + ".");
};
// 子类
function Student(name, grade) {
Person.call(this, name);
this.grade = grade;
}
Student.prototype = new Person(); // 原型链继承父类的方法
Student.prototype.constructor = Student; // 修复构造函数
// 实例化子类
let s4 = new Student("Mary", "1");
s4.sayName(); // 输出 "My name is Mary."
console.log(s4.name, s4.grade); // 输出 "Mary 1"
在这里我们既用到了原型链继承父类的方法,也通过借用构造函数继承了父类的属性,达到了全面继承的效果。
需要注意的是,由于子类的原型 Student.prototype
被重新赋值为了父类的实例 new Person()
,所以需要额外修复一下子类的构造函数指向。
4. 原型式继承
原型式继承是通过指定一个基础对象来创建子类,实现对基础对象属性和方法的继承。具体代码实现如下:
// 基础对象
let baseObj = {
name: "",
sayName: function () {
console.log("My name is " + this.name + ".");
},
};
// 创建子类
let s5 = Object.create(baseObj);
s5.name = "Linda";
s5.sayName(); // 输出 "My name is Linda."
console.log(s5.name); // 输出 "Linda"
在这里我们用 Object.create
方法创建了一个新对象 s5
,并指定了基础对象 baseObj
作为它的原型,从而实现了对基础对象的属性和方法的继承。
5. 寄生式继承
寄生式继承是在原型式继承的基础上增强了对象的功能。具体代码实现如下:
// 基础对象
let baseObj2 = {
name: "",
sayName: function () {
console.log("My name is " + this.name + ".");
},
};
// 增强对象的功能
let subObj = Object.create(baseObj2);
subObj.sayHi = function () {
console.log("Hi, I am " + this.name + ".");
};
// 创建子类
let s6 = Object.create(subObj);
s6.name = "John";
s6.sayHi(); // 输出 "Hi, I am John."
console.log(s6.name); // 输出 "John"
在这里我们对原型式继承创建的对象 subObj
增加了一个 sayHi
方法,然后在它的基础上创建了新对象 s6
。新对象依然继承了 baseObj2
的属性和方法,同时也有了自己的方法 sayHi
。
6. 寄生组合式继承
寄生组合式继承是在组合继承的基础上进行了优化,避免了父类构造函数被调用两次的问题。具体代码实现如下:
// 父类
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function () {
console.log("My name is " + this.name + ".");
};
// 子类
function Student(name, grade) {
Person.call(this, name); // 借用构造函数继承属性
this.grade = grade;
}
Student.prototype = Object.create(Person.prototype); // 原型式继承方法
Student.prototype.constructor = Student; // 修复构造函数
// 实例化子类
let s7 = new Student("Lucy", "4");
s7.sayName(); // 输出 "My name is Lucy."
console.log(s7.name, s7.grade); // 输出 "Lucy 4"
在这里我们使用 Object.create
方法实现了对父类原型 Person.prototype
的继承,同时用 call
方法调用了父类构造函数,并且也修复了子类的构造函数。
以上就是 JavaScript 实现继承的六种方式的详细攻略和示例说明。希望能够对你有所帮助!
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript是如何实现继承的(六种方式) - Python技术站