面向对象编程最重要的方面之一是对象的继承。 通过继承对象 B,对象 A 直接拥有对象 B 的所有属性和方法。这对于重用非常有用。
大多数面向对象的编程语言都使用类来实现对象继承。 传统上,j**ascript 语言中的继承不是通过类实现的(ES6 引入了类语法),而是通过“原型”来实现的。 那么JS中常见的继承方法有多少呢?
这种方法的关键是:子类型的原型是父类型的实例对象。
父类型 函数 人(姓名、年龄) 人prototype.setage = 函数 () 子类型 函数 student(price) studentprototype = new person() 子类型的原型是父类型的实例对象,var s1 = new student(15000),var s2 = new student(14000) consolelog(s1,s2)
但这种方法的本质是将子类的原型指向父类的实例,因此然后,学生可以访问子类的实例prototype 也是 person 的一个实例,这样就可以访问父类的私有方法,然后通过 proto 指向父类的原型,获取父类原型上的方法。因此,父类的私有和公共方法和属性被视为子类的公共属性。
子类继承父类的属性和方法,并将父类的私有属性和公共方法视为自己的公共属性和方法如果父类的私有属性中有引用类型属性,那么当它被子类继承时,它将被用作公共属性,因此当子类 1 操作该属性时,它将影响子类 2。
s1.play.push(4)console.log(s1.play, s2.play)console.log(s1.__proto__ === s2.__proto__)=== s2.__proto__.proto__)//true
play 属性在 S1 中发生了变化,play 属性在 S2 中也发生了变化。
另一件需要注意的事情是,当我们需要向子类添加新方法或重写父类中的方法时,请务必将其放在替换原型的语句之后
function person (name, age) person.prototype.setage = function ()function student (price) }// student.prototype.sayhello = function() 在这里写原型方法和子类的属性是无效的,因为它会改变原型的方向,所以应该放在重新命名之后prototype = new person()student.prototype.sayhello = function ()var s1 = new student(15000)console.log(s1)
特征:
父类的新原型方法 prototype 属性对于所有子类都很简单且易于实现缺点:
不可能实现所有实例共享的原型对象的所有属性的多个继承在创建子类实例时,无法将参数传递给父类构造函数为了向子类添加属性和方法,必须使用student.prototype = new person()
之后,不将其放入构造函数的关键如下:在子类型构造函数中,泛型 call() 调用父类型构造函数
function person(name, age) person.prototype.setage = function ()function student(name, age, price) var s1 = new student('tom', 20, 15000)
这种方法只实现部分继承,如果父类原型也有方法和属性,则子类将无法获取它们。
console.log(s1.setage())//uncaught typeerror: s1.setage is not a function
特征:
解决了原型链继承中子类实例共享父类引用属性的问题,在创建子类实例时,可以将参数传递给父类,并实现多重继承(调用多个父类对象)缺点:
实例不是父类的实例,但子类的实例只能继承父类的实例属性和方法,不能继承原型的属性和方法来实现函数复用通过调用父类构造,继承父类的属性并保留传递参数的优点,然后使用父类实例作为子类原型,该函数被重用。
function person (name, age) }person.prototype.setage = function ()function student (name, age, price) }student.prototype = new person()student.prototype.constructor = 学生 组合继承也是学生。 构造函数指向的需要修复prototype.sayhello = function ()var s1 = new student('tom', 20, 15000)var s2 = new student('jack', 22, 14000)console.log(s1)console.log(s1.constructor) //person
这种方法结合了原型链继承和构造函数的优点,是 j**ascript 中最常用的继承模式。 缺点是构造函数在任何情况下都会被调用两次:一次是在创建子类型的原型时,一次是在子类型构造函数中,该构造函数最终包含父对象的所有实例属性,但是在调用子类构造函数时,我们必须覆盖这些属性。
优点:
可以继承实例属性方法,也可以继承原型属性方法,不存在引用属性共享问题,参数函数可以复用缺点:
父构造函数被调用了两次,导致两个实例这样,父类原型和子类原型指向同一个对象,子类可以作为自己的公共方法继承到父类的公共方法,并且不初始化两次实例方法属性,避免了组合继承的缺点
function person (name, age) }person.prototype.setage = function ()function student (name, age, price) }student.prototype = person.prototypestudent.prototype.sayhello = function ()var s1 = new student('tom', 20, 15000)console.log(s1)
但是,无法判断对象是子实例化还是父实例化。
console.log(s1 instanceof student, s1 instanceof person)//true trueconsole.log(s1.constructor)//person
优点:
双实例方法属性不初始化,避免了组合继承的弊端缺点:
无法判断实例是由子类还是父类创建的,并且子类和父类的构造函数指向相同的实例。 原型允许您根据已有的对象创建对象var b = object.create(a)
基于对象 A,生成对象 B。 B 继承了 A 的所有属性和方法。
function person (name, age) person.prototype.setage = function ()function student (name, age, price) }student.prototype = object.create(person.原型)核心**学生prototype.constructor = Student core**var s1 = new student('tom', 20, 15000)console.log(s1 instanceof student, s1 instanceof person) // true trueconsole.log(s1.constructor)
同样,学生继承 Person 原型对象的所有属性和方法。 至此,完美的传承方法!
ES6 引入了 class 关键字,可以通过 extends 关键字继承,也可以通过 static 关键字定义类的静态方法,这比通过修改原型链来实现继承的 ES5 更清晰、更方便。
ES5 中的继承本质上是创建一个子类 this 的实例对象,然后在 this(parent.)之上添加父类的方法。apply(this))。ES6 有一个完全不同的继承机制,本质上是将父类实例对象的属性和方法添加到这个对象中(所以你必须先调用 super 方法),然后用子类的构造函数修改它。
需要注意的是,class 关键字只是原型的句法糖,j**ascript 继承还是基于原型的
class person 定义通用方法 showname()let p1 = new person('kobe', 39)console.log(p1) 定义了一个子类: class student extends person showname () let s1 = new student('wade', 38, 1000000000)console.log(s1)s1.showname()
优点:
语法简单易懂,操作更方便缺点:
不是所有的浏览器都支持 class 关键字js 几种实现继承的方法j**ascript 多种方式和深度继承的优缺点j**ascript 常用继承方法阮一峰 es6 入门类继承方法 5:组合继承优化 2 我觉得也可以这样写:
function person (name, age) person.prototype.sayname = function() function student (name, age, price) student.prototype = object.create(person.prototype);student.prototype.constructor = student;这里将 sayage 原型方法放在继承语句之后,以防止 s1sayage() 错误,详见方法二:借用构造函数继承 studentprototype.sayage = function() var p1 = new person('join', 30);var s1 = new student('tom', 20, 1500);console.log(p1.sayname())// joinconsole.log(s1.sayage())// 20