JavaScript中的原型与继承

原型

在JavaScript中,函数是一个包含属性和方法的Function类型的对象。而原型(Prototype)就是Function类型对象的一个属性
在函数定义时就包含prototype属性,它的初始值是一个空对象。在JavaScript中并没有定义函数的原型类型,所以原型可以是任何类型
原型是用于保存对象的共享属性和方法的,原型的属性和方法并不会影响函数本身的属性和方法

function foo(a,b){
    return a+b;
}
console.log(typeof foo.prototype);//object
获取原型

通过如下两种方式可以获取对象的原型,从而设置共享的属性和方法:

  • 通过构造函数的prototype属性
function Person(){
    console.log('Person instantiated');
}
console.log(Person.prototype);
  • 通过Object对象的getPrototypeOf(obj)方法
function Person(){
    console.log('Person instantiated');
}
console.log(Object.getPrototypeOf(Person));
原型的属性和方法

通过如下两种方式可以设置原型的属性和方法:

  • 原型的属性和方法单独进行定义

构造函数.prototype.属性名=属性值;
构造函数.prototype.方法名=function(){}

  • 直接为原型定义一个新对象

构造函数.prototype={

属性名:属性值,
方法名:function(){}

}

自有属性与原型属性
  • 自有属性:通过对象的引用添加的属性。其它对象可能无此属性;即使有,也是彼此独立的属性
  • 原型属性:从原型对象中继承来的属性,一旦原型对象中属性值改变,所有继承自该原型的对象属性均改变
function Emp(ename,salary){
    this.ename=ename;
    this.salary=salary;
}
Emp.prototype={city:'北京市',dept:'研发部'}
var emp1=new Emp('Mary',3800);
var emp2=new Emp('Tom',3000);
检测自有或原型属性
  • 使用hasOwnPrototype()方法检测对象是否具有指定的自有属性:
function Hero(){}
var hero=new Hero();
console.log(hero.hasOwnPrototype('name'));
  • 使用in关键字检测对象及其原型链中是否具有指定属性:
function Hero(){}
var hero=new Hero();
console.log('name' in hero);
扩展属性或方法

通过原型可以为指定构造函数或对象扩展其属性或方法,如下代码示例:

function Hero(){}
Hero.prototype={
    name:'Mary',
    salary:3800
}

var hero=new Hero();
console.log(hero.name);//Mary
重写原型属性

通过构造函数或对象的自有属性可以重写原型的属性,如下代码示例:

function Hero(){}

Hero.prototype={
    name:'Mary',
    salary:3800
}

var hero=new Hero();
hero.name='Tom';

console.log(hero.name);//Tom
删除属性

通过delete关键字可以删除对象的属性,如果该对象既具有原型属性又具有自有属性的话,先删除自有属性,再删除原型属性。如下代码示例:

function Hero(){}
Hero.prototype={name:'Mary',salary:3800}

var hero=new Hero();
hero.name="Tom";

delete hero.name;//删除 Tom
console.log(hero.name);//Mary

delete hero.name;//删除 Mary
console.log(hero.name);//undefined
isPrototypeOf()方法

每个对象中都会具有一个isPrototypeOf()方法,该方法用来判断一个对象是否是一个对象的原型

var monkey={}
function Human(){}
Human.prototype=monkey;

var man=new Human();

monkey.isPrototypeOf(man);//true
__Proto__属性
function Hero(){}

Hero.prototype={
    name:'Mary',
    salary:3800
}

var hero=new Hero();
console.log(hero.name);//Mary

上述代码说明hero对象存在一个指向构造函数Hero的原型,这个链接被叫做__proto__属性
需要注意的是:__proto__属性与prototype属性并不等价。__proto__属性只能在调试时使用

  • __proto__属性是指定对象的属性
  • prototype属性是指定构造函数的属性
扩展内建对象

JavaScript中的内置对象有些也具有prototype属性,利用内置对象的prototype属性可以为内置对象扩展属性或方法
通过原型扩展内置对象的属性和方法非常灵活,根据个性化要求制定JavaScript语言的具体内容。一般建议慎用这种方式,如果JavaScript的版本更新时可能会提供个性化的属性或方法,导致冲突。

Array.prototype.inArray=function(color){
   for(var i=0,len=this.length;i<len;i++){
    if(this[i]===color){return true;}
    }
    ruturn false;
}
var a=['red','green','blue'];

console.log(a.inArray('red'));//true
console.log(a.inArray('yellow'));//false

继承

原型链

构造函数或构造器具有prototype属性,对象具有__proto__属性,这就是之前学习的原型
如果构造函数或对象A,A的原型指向构造函数或对象B,B的原型再指向构造函数或对象C,以此类推,最终的构造函数或对象的原型指向Object的原型。由此形成一条链状结构,被称之为原型链。
按照上述的描述,在B中定义的属性或方法,可以直接在A中使用并不需要定义。这就是继承,它允许每个对象来访问其原型链上的任何属性或方法
原型链是ECMAScript标准中指定的默认实现继承的方式。

原型链实现继承
function A(){
    this.name="a";
    this.toString=function(){return this.name};
}
function B(){
    this.name='b';
}
function C(){
    this.name='c';
    this.age=18;
    this.getAge=function(){return this.age};
}
B.prototype=new A();
C.prototype=new B();
只继承于原型

出于对效率的考虑,尽可能地将属性和方法添加到原型上。可以采取以下方式:

  • 不要为继承关系单独创建新对象
  • 尽量减少运行时的方法搜索
只继承于原型

根据上述方式进行更改后,代码如下:

function A(){}
A.prototype.name='a';
A.prototype.toString=function(){return this.name}

function B(){}
B.prototype=A.prototype;
B.prototype.name='b';

function C(){}
C.prototype=B.prototype;
C.prototype.name='c';
C.prototype.age=18;
C.prototype.getAge=function(){return this.age};

原型链虽然很强大,用它可以实现JavaScript中的继承,但同时也存在着一些问题。

  • 原型链实际上是在多个构造函数或对象之间共享属性和方法
  • 创建子类的对象时,不能像父级的构造函数传递任何参数

综上所述,在实际开发中很少会单独使用原型链

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值