图1 关系图解
__proto__(双横线):javascript中对象内置的隐藏属性,类似指针,指向其引用对象的原型对象。
prototype:函数对象的一个属性,也类似于一个指针,指向其原型对象。
Point{}:Point的原型对象。
Point:Point的构造函数。
如图1,定义一个函数 Point(),其中Poin对象增加p1属性,Point原型对象增加一个sum方法。p1,p2为Point()的实例化对象,name1,name2分别为p1,p2的属性。代码如下:
function Point(){
var p1 = "测试点";
}
Point.prototype.sum = function (){
var sum = function(){
return 1+2;
}
}
var P1 = new Point();
var P2 = new Poin();
P1.name1 = "点1";
P2.name2 = "点2";
P1拥有的属性和方法:sum方法,Name1属性。
P2拥有的属性和方法:sum方法,Name2属性。
javascript搜索一个对象的属性和方法,先默认搜索自身的属性和方法,如果自身没搜索到,再通过__proto__属性找到其引用对象的原型对象,如此通过__proto__一层层往下找,最终__proto__的指针指向null;
诸如:P1-->Point{}-->Object{}-->null 通过__proto__形成的一条链路,这条链路便是原型链。
通过上述代码模拟了一个Point类 ,其中p1为Point的私有属性,sum为Point的公共方法。通过new Point()建立的为Point的实例化对象,拥有Point的所有公共属性和方法。
若想获取 Point的私有属性,可以进行如下改造:
function Point(){
var p1 = "测试点";
this.getP1 = function (){
return p1;
}
}
这样,就能对Point实现封装,提供读取p1属性的方法。
有了Point类,也能进行封装了,那如何实现继承?
由关系图可知,通过 Animal.prototype = new Point(); 就可以实现继承,Animal继承了Point,拥有Point的所有公共属性和方法。A1为Animal的实例化对象,则A1 不仅拥有Animal的所有公共属性和方法,而且拥有Point的所有公共属性和方法。代码如下:
function Animal(){
var add1 = function (){ return "add1";};
this.add2 = function (){ return "add2";};
}
Animal.prototype.run = "run"; //此行不是代码内容,只是为了测试更改原型对象后此属性是否还存在。
Animal.prototype = new Point();
var A1 = new Animal();
此时A1拥有的属性和方法为:add2方法,sum方法。add1作为Animal的私有方法无法获取,run则属性Animal以前的原型对象的属性,也无法获取,sum作为Animal继承的方法,能够获取。而A1能够拥有add2方法则是因为在Javascript中,this指向函数执行时的当前对象该关键字在Javascript中和执行环境,而非声明环境有关。 this关键字虽然是在定义Animal的时候生成的,但是在new Animal()的时候才执行,因此add2得以存在。
PS:自己画的图和写的内容,非转载,刚毕业的菜鸟,如果我理解的有不对的地方欢迎大家指正。
另:原型链固然强大,但是因为javascript是动态语言,通过原型链甚至能修改继承的父类的属性和方法,还能给父类增加读写方法。关于如何防止别人随意篡改父类的属性,还请大牛们指点一二。