原型
在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中的继承,但同时也存在着一些问题。
- 原型链实际上是在多个构造函数或对象之间共享属性和方法
- 创建子类的对象时,不能像父级的构造函数传递任何参数
综上所述,在实际开发中很少会单独使用原型链
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。