一、继承的概念
让一个没有某个属性或方法的对象能够使用另一个具有某个方法或属性的对象的属性或方法。
先看一个小规模的实例和实例之间的继承:
var obj = {
name:"obj",
show:function(){
console.log(this.name);
}
}
var obj2 = {
name:"obj2"
}
如何利用show,打印出obj2的名字?
obj.show(); //结果是 obj
obj.show.call(obj2); //结果是 obj2
obj2.show();
二、继承主要有以下四种,我们分别一一列举:
- 原型的继承
- 构造函数的继承
- 混合继承(组合)
- ES6 class 继承
1、原型的继承
<script>
function Parent(){
// this.name = "parent";
}
// Parent.prototype.name = "parent";
Parent.prototype.show = function(){
console.log("哈哈哈");
}
function Child(){
}
// 浅拷贝
// Child.prototype = Parent.prototype;
// 深拷贝
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
// Child.prototype.abc = function(){
// console.log("hello");
// }
Child.prototype.show = function(){
console.log("hello");
}
var p = new Parent();
p.show();
// p.abc();
console.log(p.name);
var c = new Child();
c.show();
// c.abc();
console.log(c.name);
</script>
原型继承1 - 原型对象继承特点:
1、简单,方便,易操作;
2、但是,只能继承原型身上的方法和属性,不能继承构造函数内的方法和属性;
function Parent(n){
// this.name = "hello world";
this.name = n;
}
Parent.prototype.show = function(){
// console.log("哈哈哈");
console.log(this.name);
}
function Child(n){
// this.name = "html";
// this.name = n;
}
Child.prototype = new Parent("hello");
// Child的实例c ---> __proto__ ---> Child.prototype ---> Parent的实例 ---> __proto__ ---> Parent.prototype
// Child.prototype.show = function(){
// console.log("嘿嘿嘿");
// }
var p = new Parent("张三");
// console.log(p)
p.show();
// console.log(p.name);
var c = new Child();
// console.log(c);
c.show();
// console.log(c.name);
// c.__proto__.__proto__.show = function(){}
原型继承2 - 原型链继承:特点:
1.更加的简单,方便,易操作;
2.不仅可以继承原型身上的方法和属性,而且还可以继承构造函数中的方法和属性;
3.但是,不方便传参;
2、构造函数的继承
<script>
function Parent(s){
this.skill = s;
}
Parent.prototype.show = function(){
console.log(this.skill);
}
function Child(n){
// 利用this的改变
// this
// 在Child中执行Parent的同时,修改this指向,为Child的this
// 因为Child将来被new执行,Child中的this,指向将来Child的实例
// Parent.call(this,n);
// Parent.apply(this,[n]);
Parent.bind(this,n)();
}
var p = new Parent("大鉴定师");
console.log(p.skill);
p.show();
var c = new Child("实习鉴定师");
console.log(c.skill);
c.show();
</script>
以上是构造函数继承(改变this指向继承):特点:
1.方便的传参;
2.还可以实现多继承;
3.但是,只能继承构造函数内部的属性或方法,不能继承原型身上的属性或方法;
<script>
function Mp3(){
this.music = "放音乐";
}
function Camera(){
this.photo = "拍照";
}
function Tel(){
this.call = "打电话";
}
function Email(){
this.message = "发信息";
}
function MobilePhone(n){
Mp3.call(this);
Camera.call(this);
Tel.call(this);
Email.call(this);
this.name = n;
this.game = "打游戏";
}
var mp = new MobilePhone("HUAWEI P30");
console.log(mp);
</script>
以上是 原型继承 - 多继承;
<script>
function Parent(s){
this.skill = s;
// 测试原型链继承的参数隐患
// this.skill.split();
}
Parent.prototype.show = function(){
console.log(this.skill);
}
function Child(s){
Parent.call(this, s);
}
// Child.prototype = new Parent();
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
Child.prototype.show = function(){
console.log("hello 鉴定师");
}
var p = new Parent("大鉴定师");
p.show();
var c = new Child("实习鉴定师");
c.show();
</script>
以上是混合继承:构造函数继承 + 原型继承
1.略复杂;
2.既可以继承构造函数,又可以继承原型;
3.方便传参;
4.可以多继承构造函数;
5.注意:原型链继承时,依然有参数隐患;
6.是常用的继承方式之一。
3、ES6的class继承
<script>
class Parent{
constructor(s){
this.skill = s;
}
show(){
console.log(this.skill);
}
}
class Child extends Parent{
constructor(s){
super(s);
// this.skill = s + "哈哈";
}
// show(){
// alert(this.skill);
// }
}
var p = new Parent("大鉴定师");
p.show();
console.log(p);
var c = new Child("实习鉴定师");
c.show();
console.log(c);
</script>
ES6的class继承,原理就是:构造函数方式继承 + 原型链继承;
补充小知识: 如何区分形参和实参?答: 看函数的执行还是定义。
执行时是实参;
定义时是形参。