惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

罗磊的独立博客
Recent Announcements
Recent Announcements
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
有赞技术团队
有赞技术团队
J
Java Code Geeks
T
The Blog of Author Tim Ferriss
MyScale Blog
MyScale Blog
人人都是产品经理
人人都是产品经理
aimingoo的专栏
aimingoo的专栏
U
Unit 42
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
T
Tailwind CSS Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 三生石上(FineUI控件)
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
Hugging Face - Blog
Hugging Face - Blog
博客园 - 司徒正美
腾讯CDC
I
InfoQ
GbyAI
GbyAI
博客园_首页

博客园 - 想那风霜雪

基于web的甘特图,易度甘特图edogantt! JavaScript异常处理 - 想那风霜雪 - 博客园 一个支持Drag页面拖动的组件 - 想那风霜雪 - 博客园 main Function和Object(2) Function和Object(1) - 想那风霜雪 - 博客园 Atlas系列:从AtlasRuntime.js开始-简介 Atlas源码阅读系列之一 9)使用面向对象思想处理cookie 8)事件设计模式 7)实现抽象类 5)使用for(...in...)实现反射机制 4)公有成员\私有成员和静态成员 - 想那风霜雪 - 博客园 3)类的实现 2)深入认识JavaScript中的函数 1)JavaScript面向对象的基础 JavaScript的OO特性:Singleton单件模式 JavaScript的OO特性:私有访问限制实现 JavaScript的OO特性:继承
6)类的继承
想那风霜雪 · 2006-08-16 · via 博客园 - 想那风霜雪

    1)利用共享prototype原型对象实现继承.
    继承是面向对象开发的一个重要概念.在JavaScript中没有专门的机制来实现类的继承,但可以通过拷贝一个类的prototype到另外一个类实现继承.一种简单的继承实现如下:

fucntion class1(){
      
//构造函数
}function class2(){
      
//构造函数
}
class2.prototype
=class1.prototype;
class2.prototype.moreProperty1
="xxx";
class2.prototype.moreMethod1
=function(){
      
//方法实现代码
}
var obj=new class2();

    这样,首先是class2具有了class1一样的prototype,不考虑构造函数,两个类是等价的.随后,又通过prototype给class2 赋予了两个额外的方法,所以class2是在class1的基础上增加了属性和方法,这就实现了类的继承.
    JavaScript提供了instanceof操作符来判断一个对象是否是某个类的实例,对于上面创建的obj对象,下面两条语句都是成立的:

obj instanceof class1
obj 
instanceof class2

    表面上看,上面的实现完全可行,JavaScript也能正确理解这种继承关系,obj同时是class1和class2的实例.但是事实上是不对的,JavaScript的这种理解实际上是基于一种很简单的策略,如下,先使用prototype让class2继承于class1,再在class2中重复定义method方法:

//定义class1
function class1(){
      
//构造函数
}
//定义class1的成员
class1.prototype={
      m1:
function(){
            alert(
1);
      }
}
//定义class2
function class2(){
      
//构造函数
}
//让class2继承于class1
class2.prototype=class1.prototype;
//给class2重复定义方法method
class2.prototype.method=function(){
      alert(
2);
}
//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用两个对象的method方法
obj1.method();
obj2.method();

    (明白了,这里用prototype等于基类的prototype来实现,在改变子类的prototype属性(方法)的时候,会影响到基类的属性(方 法),这显然大大不对啦.解决的方法,应该是拷贝基类的prototype属性,而不应该是赋予.)
    这里弹出了两次对话框"2",可见,当对class2进行prototype的改变时,class1的prototype也随之改变,即使对class2 的prototype增减一些成员,class1的成员也随之改变.这里的奥秘是:
class1和class2的prototype是完全相同的,是对同一个对象的引用.
    在JavaScript中,除了基本的数据类型(数字\字符串\布尔等),所有的赋值以及函数参数都是引用传递,而不是值传递.(这与C#类似,也是
JavaScript提高性能的一个手段.)
    上面的  
class2.prototype=class1.prototype;   语句,仅仅是让class2的prototype对象引用class1的prototype,造成了基类与子类的成员定义始终保持一致的效果.
   
从这里也看到了instanceof操作符的执行机制,它就是判断一个对象是否是一个prototype的实例,因为这里的obj1和obj2都是对应于同一个prototype,所以它们instanceof的结果都是相同的。
    因此,使用prototype引用拷贝实现继承不是正确的方法.下面,利用反射机制和prototype来实现正确的类继承.

    2)利用反射机制和prototype实现继承.
    利用反射机制实现类的继承,思路如下:利用for(...in...)语句遍历出所有基类的prototype的成员,并将其赋值给子类的prototype对象,例如:

//class1
function class1(){
      
//构造函数
}
class1.prototype
={
      method:
function(){
           alert(
1);
      },
      method2:
function(){
           alert(
"method2");
      }
}
//class2
function class2(){
      
//构造函数
}
//让class2继承于class1
for(var p in class1.prototype){     //遍历class1.prototype的属性和方法
   if (class2.prototype[p] == null//如果类class2中没有此属性或方法,则进行拷贝
        class2.prototype[p]=class1.prototype[p];
}
//覆盖定义class1中的method方法
class2.prototype.method=function(){
      alert(
2);
}
//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用obj1和obj2的method方法
obj1.method();
obj2.method();
//分别调用obj1和obj2的method2方法
obj1.method2();
obj2.method2();

  
从运行结果可见,obj2中重复定义的method已经覆盖了继承的method方法,同时method2方法未受影响。而且obj1中的method方法仍然保持了原有的定义。这样,就实现了正确意义的类的继承.
    为了方便开发,可以为每个类添加一个共有的方法,用以实现类的继承:

Function.prototype.inherit = function(baseClass){
    
for (var p in baseClass.prototype){
        
if (this.prototype[p] == null){
            
this.prototype[p] = baseClass.prototype[p];
        }
    }
}

    这里使用所有函数对象(类)的共同类Function来添加继承方法,这样所有的类都会有一个inherit方法,用以实现基于prototype的继承.
   
    3)prototype.js框架中
的类继承实现机制.
    在
prototype.js框架中,首先为所有的对象定义一个extend方法:

    Object.extend方法很容易理解,它是Object类的一个静态方法(只能用"类名.方法名"的形式调用),用于将参数中source的所有属性都赋值到destination对象中,并返回destination对象.
    而

Object.prototype.extend,因为Object是所有对象的基类,因此这里是为所有对象添加一个extend方法,出于代码复用的角度,使用了如下语句:
       Object.extend.apply(this,[this,object]);
    这一句是将Object类的静态方法作为对象的方法运行,第一个参数this是指向对象实例自身(这里无所谓);第二个参数是一个数组,包括两个元素:对象本身和传进来的对象参数object.
    如下类继承实现:

//为Object类添加静态方法:extend
Object.extend = function(destination, source) {
  
for(property in source) {
     
if (destination[property] == null){
        destination[property] 
= source[property];
     }
  }
  
return destination;
}
//class1
function class1(){
      
//构造函数      
}
class1.prototype
={
      age:
"sss",
      method:
function(){
           alert(
1);
      },
      method2:
function(){
           alert(
"method2");
      }
}
class1.show 
= function(){
    alert(
"class1的静态方法");
}
//class2
function class2(){
      
//构造函数
}//覆盖定义class1中的method方法
class2.prototype.method=function(){
      alert(
2);
}
//Object.extend时,子类与父类必须一致.
Object.extend(class2.prototype,class1.prototype);   //继承常规属性和方法
Object.extend(class2,class1);                       //继承静态属性和方法

//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用obj1和obj2的method方法
obj1.method();
obj2.method();
//分别调用obj1和obj2的method2方法
obj1.method2();
obj2.method2();

class2.show();

   

posted on 2006-08-16 11:09  想那风霜雪  阅读(354)  评论()    收藏  举报