前端必会基础知识:原型和继承

1、理解原型对象

无论什么时候,只要创建了一个新函数,就会为该函数创建一个prototype属性,这个属性就是函数的原型对象,该原型对象还有一个constructor属性和一个__proto__属性,由一个构造函数new出来的就是实例对象,它也有__proto__属性。他们之间的关系如下:

function Person(){};  
var p=new Person();
Person.prototype==p.__proto__;    //true
Person.prototype.constructor==Person;   //true

总结:只有函数才有prototype属性,只有实例对象才有__proto__属性。

2、原型链
每个实例对象上会有一个__proto__属性,它是一个指针会指向上一层的原型对象,直到Object.prototype.__proto__ = null,表示到达最顶端,这就形成了原型链。

var A=function(){};
var a=new A();
a.__proto__==A.prototype;   //true
A.prototype.__proto__==Object.prototype;   //true
Object.prototype.__proto__==null;     true

在这里插入图片描述
3、继承
a.借助构造函数实现继承

function Parent(){
     this.name='大明'
 };
 Parent.prototype.say=function(){
      alert(this.name);
}
 function Child(){
     Parent.call(this);   //this表示Child,继承Parent的属性和方法
     this.type='child';
 }
 var p=new Child();
 console.log(p.name);    //大明
 console.log(p.type);    //child
 p.say();    //TypeError

特点:p既有name属性,也有name属性,但是没有say方法。
缺点:构造函数只能继承父类构造函数里面的方法,无法继承父类原型对象上的方法。

b.借助原型链实现继承

 function Parent(){
     this.name='大明';
     this.eat=[1,2,3];    //引用数据类型
  };
  Parent.prototype.say=function(){
       alert(this.name);
 }
  function Child(){
      this.type='child';
  }
  Child.prototype=new Parent();
  var p=new Child();
  console.log(p);   //name、type属性和say方法都有
  var p1=new Child();
  var p2=new Child();
  p1.name='小明';
  console.log(p1.name,p2.name);   //小明  大明
  p2.eat.push(4);
  console.log(p1.eat,p2.eat);    //[1,2,3,4]   [1,2,3,4]

特点:不仅可以继承父类上的方法,还可以继承父类原型上的方法。
缺点:当父类中包含引用类型属性值时,由子类创建的多个实例中,只要其中一个实例引用属性只发生修改,其他实例的引用类型属性值也会立即发生改变。

c.组合方式继承

function Parent(){
    this.name='大明';
    this.eat=[1,2,3];    //引用数据类型
 };
 function Child(){
     Parent.call(this);      //构造函数继承
     this.type='child';
 }
 Child.prototype=new Parent();    //原型链继承
 var p1=new Child();
 var p2=new Child();
 p2.eat.push(4);
 console.log(p1.eat,p2.eat);    //[1,2,3]   [1,2,3,4]

组合式继承也是实际开发中最常用的继承方式,解决了以上两种继承方式的问题。

猜你喜欢

转载自blog.csdn.net/qq_37012533/article/details/84984570