当前位置: 首页 > 图文教程 > 网络编程 > Javascript > 浅析Javascript原型继承 推荐

Javascript
jQuery中isFunction方法的BUG修复
将函数的实际参数转换成数组的方法
javascript 删除数组中重复项(uniq)
js 巧妙去除数组中的重复项
javascript下一种表单元素获取方法存在的问题
javascript 三种数组复制方法的性能对比
js 多层叠的TAB选项卡
javascript 自动标记来自搜索结果页的关键字
起点页面传值js,有空研究学习下
javascript 的Document属性和方法集合
JavaScript 使用简略语法创建对象的代码
使用JQuery进行跨域请求
jquery 经典动画菜单效果代码
jquery 常用操作方法
js提示信息jtip封装代码,可以是图片或文章
javascript面向对象的方式实现的弹出层效果代码
jquery中的sortable排序之后的保存状态的解决方法
js或css实现滚动广告的几种方案
使用JavaScript库还是自己写代码?
js 右键菜单,支持不同对象不同菜单(兼容IE、Firefox)

浅析Javascript原型继承 推荐


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-12   浏览: 53 ::
收藏到网摘: n/a

JS没有提供所谓的类继承,据说在2.0中要加入这种继承方式,但是要所有浏览器都实现2.0的特性那肯定又得N多年。 JS没有提供所谓的类继承,据说在2.0中要加入这种继承方式,但是要所有浏览器都实现2.0的特性那肯定又得N多年。昨天看了crockford 的一个视频,里面讲解了一下JS的继承方式,按照PPT里面说的,一共分了三类:Prototypal,pseudoclassical,Parasitic Inheritance。
下面主要介绍一下原型继承:When a function object is created, it is given a prototype member which is an object containing a constructor member which is a reference to the function object.


这里先区别一下什么是prototype属性,和constructor属性。也就是要区别什么是构造器,函数,对象实例。

其实在JS中构造器就是函数,函数就是构造器,对象实例就是通过var obj=new 函数();这种形式新建出来的实例。区别这些,在说prototype和constructor。从上面的英文中可以看出,prototype是个对象,里面定义了一个constructor,那么我们可以推论出,constructor是对象实例的属性!而不是函数(构造器)的属性。反过来,prototype是函数(构造器)的属性,而不是实例的属性!
复制代码 代码如下:
复制代码 代码如下:

//方法一
//Prototype框架采用了此种方法
Hoozit.prototype = new Gizmo(2);
Hoozit.prototype.constructor = Hoozit;
//方法二
function Hoozit(id) {
this.id = id;
this.constructor=Hoozit;
}
//具体两种方法有什么区别,请参考《JAVASCRIPT语言精髓与编程实践》158~159页。

有兴趣的可以结合上面的图,想想这两种方法的Hoozit.prototype.constructor应该放在图的什么位置?想不明白的可以和我在交流。
下面看一下《JAVASCRIPT语言精髓和编程实践》书上的一张图(156~157页):

个人认为这张图下面的那个constructor属性的指向是不是有问题?书上面表达的意思肯定没有问题,但这张图画的很困惑。和我上面的解释不太一样?先不说这个了,大家自己研究研究吧。
下面我们再来说一下我给出的原型继承图中的右边灰色的箭头部分。从这部分能够看出继承的关系。所有未经过变动的函数(构造器)的原型,他们都会继承自Object对象。
alert(Gizmo.prototype instanceof Object.prototype.constructor); //true
这样原型的继承关系就连接起来了。其实说白了,就是一个函数的prototype链向另一个函数实例,然后不断的这样进行下去,最上面的函数链接Object至对象实例,OK,所有函数就都连接起来了。
PS:
“还有要注意的是只有在new Gizmo()之后,才能添加test等其它方法,这个顺序不能倒过来!“ 这个问题是不是清楚了呢?
下面看几个例子,说明几个问题:
复制代码 代码如下:

function Gizmo(id) {
this.id = id;
this.ask=function(){
alert("gizmo--ask:"+this.id);
}
function privateMethod(){
return "gizmo--privateMethod";
}
privateMethod2=function(){
return "gizmo--privateMethod2";
}
}
Gizmo.prototype.toString = function () {
return "gizmo--toString:" + this.id;
};
Gizmo.prototype.id="gizmo3";
function Hoozit(id) {
this.id = id;
}
Hoozit.prototype = new Gizmo("gizmo1");
var g=new Gizmo("gizmo2");
var h=new Hoozit("hoozit");

问题一:
复制代码 代码如下:

h.ask=function(){
alert("h.ask");
}
h.ask();
delete h.ask; //"h.ask"
h.ask(); //"gizmo--ask:hoozit"
delete h.id
h.ask(); //"gizmo--ask:gizmo1"
delete Hoozit.prototype.id
h.ask(); //"gizmo--ask:gizmo3"
/*
这里要说明的问题是:对象是如何找到属性和方法的?
第一步:先在实例对象上找ask方法,找到了,调用。第一个ask说明了这个问题
第二步:如果实例上没有ask方法,在自己的原型对象里面找ask方法,找到调用(没有给出这样的示例)
第三步:如果自己的原型中没有,回溯原型链,在父原型链中找ask方法,找到调用,第二个ask说明了这个问题,这里会一直递归找到Object对象,如果还没找到,那就会报错了
*/
/*
再来看属性查找:
首先找实例对象上的属性,所以第二个ask输出"gizmo--ask:hoozit",即id="hoozit"
然后找自己原型中的属性,删除掉h.id之后,找到原型上的属性,所以id="gizmo1"
接着递归原型链,找父对象原型中的属性,一直找到Object对象,所以删除掉Hoozit.prototype.id之后,id="gizmo3"
*/

问题二:
复制代码 代码如下:

Gizmo.prototype.question = function () {
alert("gizmo--question:" + this.id);
};
h.question();
/*
方法可以随时添加,添加完之后就可以调用
*/

问题三:
复制代码 代码如下:

Hoozit.prototype.toString = function () {
return "hoozit--toString:" + this.id;
};
alert(h);
delete Hoozit.prototype.toString;
alert(h);
/*
这个问题和问题一有些重复,这里更清楚的看出,删除掉自己原型上的方法之后,就会找父原型中的方法
*/

问题四:
复制代码 代码如下:

h.question.call(g);
alert(h.toString.call(g));
h.question.apply(g);
alert(h.toString.apply(g));
/*
可以利用apply和call方法把要调用的方法绑定到其它实例。通过结果可以看出上面那种方法调用输出的id是g对象的,而不是h对象的
*/

问题五:
复制代码 代码如下:

alert(h.privateMethod());
alert(g.privateMethod2());
/*
上面的任意一个调用都会报错,也就是说通过显示命名函数或者匿名函数但是不加this的声明方式定义在函数之内的函数,是不能被外界访问的。这里一定注意第二种private方法声明,省略了this外面就访问不到了!
*/
/*
命名函数:(函数名字为func1)
function func1(){}
匿名函数:(注意这里,func1不是函数的名字,仅仅是个别名而已,可以通过func()来调用这个匿名函数)
func1=function(){}
*/

pdf文件下载/upload/tech/20091012/20091012100240_6883966fd8f918a4aa29be29d2c386fb.rar