JavaScript使用对象笔记5:使用原型(JavaScript)

在JavaScript中,构造函数拥有原型,实例对象通过prototype关键字可以访问原型,实现JavaScript原型继承机制。

定义原型

原型实际上就是一个数据集合,即普通对象,继承与Object类,由JavaScript自动创建并依附于每个构造函数。

说明:JavaScript暂不支持类的概念,所谓的类就是构造函数。Function和Object都是两个不同类型的构造函数,使用new运算符可以创建不同类型的实例对象。

通过function.prototype方式定义原型。

function p(x){	//构造函数
	this.x=x;	//声明本地属性,并初始化为参数x
}
p.prototype.x=1;	//添加原型属性x,赋值为1
var p1=new p(10);	//实例化对象,并设置参数为10
alert(p1.x);	//10
alert(p.prototype.x);		//1
p.prototype.x=p1.x;		//设置原型属性值为本地属性值
alert(p.prototype.x);	//10

比较原型属性和本地属性

定义一个构造函数并为实例对象定义本地属性。

function f(){	//	声明一个构造函数
	this.a=2;	//本地属性
	this.b=function(){	//本地方法
		return this.a;
	};
}
var e=new f();	//实例化构造函数
alert(e.a);		//2
alert(e.b());	//2
e.a=22;
alert(e.a);		//22
alert(e.b());	//22

实例化对象继承了构造函数的本地属性,可以在本地修改实例对象的属性和方法。
如果构造函数定义了与原型属性同名的本地属性,则本地属性会覆盖原有的属性值。
如果使用delete运算符删除本都属性,则原型属性会被访问。

本地属性可以在实例对象中修改,但是不同的实例对象之间不会相互干扰。

function f(){	//	声明一个构造函数
	this.a=2;	//本地属性
	this.b=function(){	//本地方法
		return this.a;
	};
}
var e=new f();	//实例化构造函数
var g=new f();	//实例化构造函数
alert(e.a);		//2
alert(e.b());	//2
e.a=22;
alert(e.a);		//22
alert(e.b());	//22

alert(g.a);		//2
alert(g.b());	//2

原型属性将会影响所有实例对象,修改任何原型属性值,则该构造函数的所有实例都会看到这种变化。

function f(){
	this.a=11;
	f.prototype.b=9;
	this.c=function(){
		return this.a;
	};
}
var f1=new f();
var f2=new f();
alert(f1.b);	//9
alert(f2.b);	//9
f.prototype.b=55;
alert(f1.b);	//55
alert(f2.b);	//5

原型属性和原型方法可以在构造函数结构体内定义。

function f(){
	f.prototype.a=33;
	f.prototype.b=function(){
		return f.prototype.a;
	};
}
var f1=new f();
alert(f1.a);	//33

prototype属性属于构造函数,所以必须使用构造函数通过点语法来调用prototype属性,再通过prototype属性来访问原型对象。

应用原型

利用原型为对象设置默认值。当原型属性与本地属性同名时,它们之间可以出现交流现象。可以利用这种现象为对象初始化默认值。

function f(x){
	if(x){
		this.x=x;
	}
}
f.prototype.x=22;
var f1=new f();	
alert(f1.x);	//22
var f2=new f(34);
alert(f2.x);	//34

利用原型间接实现本地数据备份。把本地对象的数据完全赋值给原型对象,相当于为该对象定义一个副本,通俗地说就是备份对象。这样当对象属性被修改时,可以通过原型对象来恢复本地对象的初始值。

function f(x){
	this.x=x;
}
f.prototype.backup=function(){
	for(var i in this){
		f.prototype[i]=this[i];
	}
}
var f1=new f(2);
alert(f1.x);	//2
f1.backup();
alert(f1.x);	//2
f1.x=55;
alert(f1.x);	//55
f1=f.prototype;
alert(f1.x);	//2

利用原型还可以为对象属性设置“只读”特性,这在一定程度上可以避免对象内部数据被任意修改的尴尬。

利用原型进行批量复制。

function f(x){
	this.x=x;
}
var a=[];
function temp(){}
temp.prototype=new f(10);
for(var i=0;i<100;i++){
	a[i]=new temp();
}

原型域和原型域链

在JavaScript中,实例对象在读取属性时,总是先检查自身域属性,如果存在,则会返回本地属性值,否则就会往上检索prototype原型域,如果找到同名属性,则返回prototype原型域中的原型属性。

prototype原型域可以允许原型属性引用任何类型的对象。如果在prototype原型域中没有找到指定的属性,则JavaScript将会跟腱炎引用关系,继续向外查找prototype原型域所指向对象的prototype原型域,直到对象的prototype域为它自己,或者出现循环为止。

原型域链能够帮助用户更清楚地认识JavaScript面向对象的本质。每个对象实例都有属性成员用于指向它的构造函数的原型(prototype),可以把这种层层指向父原型的关系称为原型域链(prototype chain)。

在JavaScript中,一切都是对象,函数是第一型。Function和Object都是函数的实例。构造函数的父原型指向Function的原型

Function.prototype.a=function(){	//Function原型方法
	alert("Function");
}
Object.prototype.a=function(){	//	Object原型方法
	alert("Object");
}
function f(){	//构造函数f
	this.a="a";
}
f.prototype={	//构造函数f的原型方法
	w:function(){
		alert("w");
	}
}
alert(f instanceof Function);	//true,说明f是Function的实例
alert(f.prototype instanceof Object);	//true,说明f原型也是对象
alert(Function instanceof Object);	//true,说明Function是Object的实例
alert(Function.prototype instanceof Object);	//true,说明Function的原型是Object的实例
alert(Object instanceof Function);	//true,说明Object是Function的实例
alert(Object.prototype instanceof Function);	//false,说明Object.prototype是所有父原型的顶层

原型继承

原型继承是一种简化的继承机制,也是JavaScript主要支持的一种继承方式。在原型继承中,类和实例化概念淡化了,一切都从对象的角度来考虑。原型继承不再需要使用类来定义对象的结果,直接定义对象,并被其他对象引用,这样就形成了一种继承关系,其中引用对象被称为原型对象(Property Object)。JavaScript能够根据原型链来查找对象之间的这种继承关系。

使用原型继承父方法设计类型继承。

function A(X){	//A类
	this.x1=x;
	this.get1=function(){
		return this.x1;
	}
}
function B(x){	//B类
	this.x2=x;
	this.get2=function(){
		return this.x2+this.x2;
	}
}
B.prototype=new A(1);//原型对象继承A的实例
function C(x){	//C类
	this.x3=x;
	this.get3=function(){
		return this.x2*this.x2;
	}
}
C.prototype=new B(2);	//原型对象继承B的实例
var f1=new B(2);
var f2=new C(3);
alert(f1.x1);	//1
alert(f2.x1);	//1
alert(f1.get2());	//4
alert(f2.get3());	//9
alert(f2.get2());	//4

prototype的最大特点是能够允许对象实例共享原型对象的成员。因此如果把某个对象作为一个类型的原型,那么说这个类型的实例以这个对象为原型。

基于原型的编程是面向对象编程的一种特定形式。在这种编程中,不需要声明静态类,而是通过复制已经存在的原型对象来实现继承关系的。

原型继承缺点:

  • 每个类型只有一个原型,所以它不直接支持多重继承。
  • 它不能很好地支持多参数或者动态参数的父类,也许在原型继承阶段,用户还不能决定以什么参数来实例化构造函数。
  • 使用不够灵活。用户需要在原型声明阶段实例化父类对象,并把它作为当前类型的原型, 这限制了父类实例化的灵活性,很多时候无法确定父类对象实例化的时机和场所。
  • prototype属性固有的副作用。

扩展原型方法

JavaScript允许为基本数据类型定义方法。通过Object.prototype添加原型方法,可以使得该方法对所有的对象可用。这样的方式对函数、数组、字符串、数字、正则表达式和布尔值都适用。

Function.prototype.method=function(name,func){
	this.prototype[name]=func;
	return this;
};
Number.method('integer',function(){
	return Math[this<0?'ceil':'floor'](this);
});
document.write((-10/3).integer());	//-3
String.method('trim',function(){
	return this.replace(/^\s+|\s+$/g,'');
});
document.write('"'+"  abc  ".trim()+'"');	//"abc"

通过为基本类型扩展方法,可以大大提高语言的表现力。由于JavaScript原型继承的本质,所有原型方法立即被赋予到所有的实例,即使该实例在原型方法被创建之前就创建好了。
基本类型的原型是公共结构,所以在扩展基类时务必小心,避免覆盖掉基类的原生方法。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值