js实现继承属性和方法
- 1 使用extends实现继承
- 2 原型链继承
- 3 组合继承
- 4 寄生组合继承
- 5 实例继承
- 6 拷贝继承
- 7 扩展
-
- 7.1 函数中方法定义在函数内部、函数外、prototype上的区别
- 7.2 class创建实例与构造函数创建实例
首先定义一个父类
function Animal (name, age) {
this.name = name
this.age = age
this.eat = function () {
console.log('吃', this.name, this.age)
}
}
Animal.prototype.drink = function () {
console.log('喝', this.name, this.age)
}
// 实验一下
const test = new Animal('狗', 3)
test.eat()
test.drink()
console.log(test)
运行结果
1 使用extends实现继承
最简便的继承方式,仅支持ES6+
class Dog extends Animal {
constructor(name, age, breed) {
super(name, age)
this.breed = breed
}
cry () {
console.log('叫', this.name, this.age, this.breed)
}
}
// 实验一下
const dog = new Dog('狗', 3, '田园犬');
dog.eat()
dog.drink()
dog.cry()
console.log(dog)
实验结果
2 原型链继承
function Dog (name, age, breed) {
Animal.call(this, name, age);
this.breed = breed;
this.cry = function () {
console.log('叫', this.name, this.age, this.breed)
}
}
Dog.prototype = new Animal()
Dog.prototype.constructor = Dog
// 实验一下
const dog = new Dog('狗', 3, '田园犬');
console.log(dog)
dog.eat()
dog.drink()
dog.cry()
实验结果
3 组合继承
function Dog (name, age, breed) {
Animal.call(this, name, age);
this.breed = breed;
this.cry = function () {
console.log('叫', this.name, this.age, this.breed)
}
}
Dog.prototype = Object.create(Animal.prototype)
Dog.prototype.constructor = Dog
// 实验一下
const dog = new Dog('狗', 3, '田园犬');
console.log(dog)
dog.eat()
dog.drink()
dog.cry()
实验结果
4 寄生组合继承
function Dog (name, age, breed) {
Animal.call(this, name, age);
this.breed = breed;
this.cry = function () {
console.log('叫', this.name, this.age, this.breed)
}
}
(() => {
let Super = function () { };
Super.prototype = Animal.prototype;
Dog.prototype = new Super();
Dog.prototype.constructor = Dog;
})();
// 实验一下
const dog = new Dog('狗', 3, '田园犬');
console.log(dog)
dog.eat()
dog.drink()
dog.cry()
实验结果
5 实例继承
function Dog (name, age, breed) {
let dog = new Animal(name, age);
dog.breed = breed;
dog.cry = function () {
console.log('叫', this.name, this.age, this.breed)
}
return dog
}
// 实验一下
const dog = new Dog('狗', 3, '田园犬');
console.log(dog)
dog.eat()
dog.drink()
dog.cry()
实验结果
6 拷贝继承
function Dog (name, age, breed) {
let animal = new Animal(name, age);
for (let key in animal) {
this[key] = animal[key]
}
this.breed = breed;
this.cry = function () {
console.log('叫', this.name, this.age, this.breed)
}
}
// 实验一下
const dog = new Dog('狗', 3, '田园犬');
console.log(dog)
dog.eat()
dog.drink()
dog.cry()
实验结果
7 扩展
7.1 函数中方法定义在函数内部、函数外、prototype上的区别
- 挂载在函数内部的方法,实例内部会复制构造函数的方法
- 挂载在原型上的方法,不会去复制。
- 挂载在内部和原型上的方法都是可以通过实例去调用的
- 一般来说,如果需要访问构造函数内部的私有变量,我们可以定义在函数内部,其他情况我们可以定义在函数的原型上
- 在函数外定义的方法,只能用类调用
函数位置 | 调用方式 | 结果 |
---|---|---|
构造函数内 | 函数名直接调用 | 报错 |
函数外 | 函数名直接调用 | 正常执行 |
函数外 prototype上 | 函数名直接调用 | 报错 |
构造函数内 | 实例化对象调用 | 正常执行 |
函数外 | 实例化对象调用 | 报错 |
函数外 prototype上 | 实例化对象调用 | 正常执行 |
7.2 class创建实例与构造函数创建实例
function exa1 (name, age) {
this.name = name
this.age = age
this.innerFunc = function () {
console.log('inner')
}
}
exa1.prototype.outerFunc = function () {
console.log('prototype')
}
exa1.getClassName = function () {
console.log('example')
}
class exa2 {
constructor(name, age) {
this.name = name
this.age = age
}
innerFunc = function () {
console.log('inner')
}
outerFunc () {
console.log('prototype')
}
static getClassName () {
console.log('example')
}
}
console.log(new exa1(), new exa2())