JavaScript---继承
JavaScript---继承
JavaScript语言的继承机制---由于JavaScript没有‘类(class)’和‘实例(instance)’的概念,他是靠‘原型链(prototype chain)’模式来实现继承的
要理解JavaScript的继承机制,首先,要清楚这几个概念:构造函数,实例对象,prototype,constructor、__proto__ 以及他们之间的关系。
构造函数:用来初始化新创建的对象的函数是构造函数。(你可以把构造函数看成是“类”)
实例对象:通过构造函数的new操作创建的对象是实例对象。可以用同一个构造函数,构造多个实例对象。
prototype:每个函数(当然包括构造函数)都有一个prototype属性,它是一个对象。我们称它为‘原型对象’ prototype:{...}
constructor:每个对象都有一个constructor属性,它是一个函数:constructor:fn(){...} 它的作用就是指向该原型对象对应的构造函数。由于实例对象可以继承原型对象的属性,所以实例对象也拥有constructor属性,同样指向原型对象对应的构造函数
__proto__:每个实例对象都有一个proto属性,指向创建该实例对象的构造函数的原型对象(可以理解为 实例对象---》构造函数的原型对象)
熟练使用JavaScript的继承必须要对这几个概念烂熟于心。
接下来结合图示来分析一下。
要想清楚的了解JavaScript的继承机制,这些概念是必须烂熟于心的。
JavaScript的继承 ---指的是子类继承父类的属性和方法
JavaScript的继承特点:1.子类拥有父类所有的属性和方法(代码复用);2.子类可以扩展自己的属性和方法(更加灵活);3.子类可以重写父类的方法
JavaScript的继承方式
1.组合继承
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>组合继承法</title> <script> function Person(name,age,gender,geyan){ this.name = name; this.age = age; this.gender = gender; this.geyan = geyan; } Person.prototype.say = function(){ console.log(`我叫${this.name},${this.gender},我今年${this.age}岁,我的人生格言是:${this.geyan}`); } var p1 = new Person('lx',18,'男','我姓谢,王菲的哪个谢'); var p2 = new Person('lw',45,'男','你有困难我帮忙,我住隔壁,我姓王'); p1.say(); p2.say(); function Student(){ // 借用构造函数法 // Person.call(this,name,age,gender,geyan) Person.apply(this,arguments); } //原型链继承法 Student.prototype = new Person(); var s1 = new Student('小明', 12, '男', '姐姐,约吗'); s1.say(); console.log(s1); </script> </head> <body> </body> </html>
chrome显示如下:
组合继承主要使用:1.借用构造函数法--使用call方法或apply方法借用父类的属性,使子类可以使用。 2.原型链继承法---将父类的实例对象赋给子类的原型对象,这样,子类的原型对象就继承到了父类的原型对象里的方法(子类原型对象---》父类原型对象)
组合继承的弊端:1.多次执行了父类构造函数 在我们的例子中, 每创建一个子类的实例sn,都要调用一次父类构造函数 ,很麻烦。 2.在原型对象里生成多余的属性 原因在于原型链继承这一步中,父类的实例对象的属性也被子类的原型对象继承了。
知道他的弊端之后,就能加以改进了:将原型链继承法用新的方法替代,这个新的方法叫做:原生式继承法。这个方法不会生成多余的属性
来看改进过的代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>组合继承法</title> <script> function Person(name,age,gender,geyan){ this.name = name; this.age = age; this.gender = gender; this.geyan = geyan; } Person.prototype.say = function(){ console.log(`我叫${this.name},${this.gender},我今年${this.age}岁,我的人生格言是:${this.geyan}`); } var p1 = new Person('lx',18,'男','我姓谢,王菲的哪个谢'); var p2 = new Person('lw',45,'男','你有困难我帮忙,我住隔壁,我姓王'); p1.say(); p2.say(); function Student(){ // 借用构造函数法 // Person.call(this,name,age,gender,geyan) Person.apply(this,arguments); } //原生式继承法 function object(o){ function F(){} F.prototype = o; return new F(); } Student.prototype = object(Person.prototype); var s1 = new Student('小明',12, '男', '姐姐,约么?'); s1.say(); console.log(s1); </script> </head> <body> </body> </html>
在chrome中显示:
原生式继承法的精髓在于:直接继承父类的原型,而不是向原型链继承那样继承整个父类。但这样又带来了一个新的问题:每次继承都要写一长串的代码。
怎么偷懒? 好在ES5给我们拓展了关于原型的继承方法----子类.prototype = Object.create(父类.prototype);
再看一下改进的代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>组合继承法</title> <script> function Person(name,age,gender,geyan){ this.name = name; this.age = age; this.gender = gender; this.geyan = geyan; } Person.prototype.say = function(){ console.log(`我叫${this.name},${this.gender},我今年${this.age}岁,我的人生格言是:${this.geyan}`); } var p1 = new Person('lx',18,'男','我姓谢,王菲的哪个谢'); var p2 = new Person('lw',45,'男','你有困难我帮忙,我住隔壁,我姓王'); p1.say(); p2.say(); function Student(){ // 借用构造函数法 // Person.call(this,name,age,gender,geyan) Person.apply(this,arguments); } //ES5的原型使继承法 Student.prototype = Object.create(Person.prototype); var s1 = new Student('小明',12,'男','姐姐,约么?'); s1.say(); console.log(s1); </script> </head> <body> </body> </html>
在chrome中显示:
这种原型式继承法+借用构造函数法的强力组合就是JavaScript继承方式的第2种方法 叫做寄生继承。这也是最终推荐的继承方式。
你以为结束了吗??
并
没
有
!
讲完了ES5,怎能不讲讲ES6? ES6给我们准备了一个“大礼包”!!
开头说到,JavaScript没有“类”的概念。现在有了(JavaScript一直在成长啊)!!ES6中用关键字 class 来定义一个类
先上代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ES6中的继承方式</title> <script> // 类: 使用class定义了一个类 Person class Person{ // 构造函数 所有的属性都放在constructor函数里(模仿java) constructor(name,age){ this.name = name; this.age = age; } // 所有的方法写在函数constructor外 注意:并不需要声明方法 直接 say(){...}的形式 相当于 Person.prototype.say = function(){...} say(){ console.log('say,say'); } // 静态方法 只会被子类继承, 不会被子类的实例继承 static sing(){ console.log(`我叫${this.name},我会唱歌`); } } // Person.prototype.say = function(){} var p1 = new Person('lx',18); p1.say(); // 静态方法的调用 Person.sing(); //使用extends去继承父类 class 子类 extends 父类{...} class Student extends Person{ constructor(name,age){ super(name,age); } } var s1 = new Student('小红',12); Student.sing(); s1.say() console.log(p1,s1) </script> </head> <body> </body> </html>
在chrome中显示:
是不是很强大!!! 考虑到部分浏览器还未兼容ES6的标准。所以还是推荐使用ES5的寄生继承。
JavaScript的继承机制就暂告一段落了。有问题以后补充 ----2017-03-21-20:10