JavaScript模拟Java类继承

javascript采用原型继承的方式继承一个类(javascript没有类这个概念,暂时这么称呼吧),但一些使用过Java的程序员可能习惯使用经典的类继承,但javascript原生并不支持这种方式,因此需要手动实现。这里通过定义一个定义类(defineClass)的函数实现,经测试越用越顺手。由于javascript没有访问修饰符,因此如果需要使用到private成员,请使用闭包。

 1 /* 简单的对象扩充方法
 2  */
 3 merge:function (target, origin) {
 4     for (var attribute in origin) {
 5         if (origin.hasOwnProperty(attribute)) {
 6             target[attribute] = origin[attribute];
 7         }
 8     }
 9 },
10 defineClass:function defineClass(constructor, parent, properties, statics, isSingleton) {
11
12     /* 如果为单例模式,保存实例,并在以后的调用中返回此实例
13      */
14     if (isSingleton) {
15         var oldConstructor = constructor,
16             instance;
17         constructor = function () {
18             if (instance) return instance;
19             oldConstructor.apply(this, arguments);
20             instance = this;
21         }
22     }
23
24     /* 设置原型属性,这意味着传入的构造函数的原型属性将被覆盖
25      * 重要:parent内部需要检测参数,下面将会讲到
26      */
27     constructor.prototype = parent ? new parent() : {};
28
29     /* 将自有属性复制到原型中
30      * 将静态属性复制到构造函数中,这意味着将不会继承parent的静态属性
31      */
32     Lang.merge(constructor.prototype, properties);
33     Lang.merge(constructor, statics);
34
35     /* 将构造函数更改为当前构造函数
36      * 将parent的引用保留
37      */
38     constructor.prototype.constructor = constructor;
39     constructor.prototype.parent = parent;
40     constructor.parent = parent;
41
42     /* 借用父类函数
43      */
44     constructor.borrow = function(methodName, context, args){
45         var oldParent;
46
47         if(typeof methodName === "object") {
48             args = context;
49             context = methodName;
50         }
51
52         oldParent = context.parent;
53         context.parent = parent;
54
55         if(typeof methodName === "string") {
56             constructor.prototype[methodName].apply(context, args || []);
57         } else {
58             constructor.apply(context, args || []);
59         }
60
61         context.parent = oldParent;
62     };
63     return constructor;
64 }

使用时,父类如此定义

 1 var Body = Lang.defineClass(function(x, y, shapes, sprites, detection){
 2     /* 由于类定义函数会创建父类实例作为子类的原型,因此必须检测参数
 3      * 如果没有参数,相当于调用父类的默认构造函数
 4      */
 5     if(arguments.length) {
 6         /* 使用父类方法
 7          */
 8         this.parent.borrow(this, arguments);
 9
10         /* 非基本类型请放到构造函数中而不是原型中
11          */
12         this._tasks = [];
13     }
14 }, Object, {
15     _distance: 0,
16     setX: function(x){},
17     setY: function(y){}
18 }, {
19     type: ‘Base‘
20 });

继承Body

 1 var Ninja = Lang.defineClass(function(){
 2     this.parent.borrow(this, arguments);
 3 }, Body, {
 4     _status: 1,
 5     setStatus: function(x){
 6         /* 使用父类方法
 7          */
 8         this.parent.borrow(‘setStatus‘, this, arguments);
 9     }
10 }, {});

注意,不能用此方法继承如Array等内置对象,如果你想通过定义一个类扩展Array的功能,那么在调用Array的某些方法时会出现问题,比如concat返回的数组直接包含两个对象,而不是包含两个对象中的元素。原因是虽然子类的原型链包含Array.prototype,但毕竟不是由Array直接构造,在调用某些方法时可能不会按照原始的方式执行。

时间: 2024-12-08 09:12:20

JavaScript模拟Java类继承的相关文章

javascript 模拟java 实现继承的5种方式

1.继承第一种方式:对象冒充 function Parent(username){ this.username = username; this.hello = function(){ alert(this.username); } } function Child(username,password){ //通过以下3行实现将Parent的属性和方法追加到Child中,从而实现继承 //第一步:this.method是作为一个临时的属性,并且指向Parent所指向的对象, //第二步:执行th

java类继承总结一 父类类型与子类类型之间的转化问题(转)

java类继承总结一 父类类型与子类类型之间的转化问题 本文将通过一个实例描述父类类型与子类类型之间的转化问题,这个很特殊的问题常常会导致一些潜在的危险,让你整整一个晚上都在调试程序以解决一个让人抓狂的java.lang.ArrayStoreException异常. 1. 子类数组的引用可以装换为超类数组的引用 2. 子类的引用child可以转换为父类的引用parent(这里假设parent是父类对象,child是子类对象),但却不可以通过 parent调用child的特有方法 class Em

前端form标签发送post请求,服务器用Java类继承HttpServlet,并返回数据

1.form表单提交: <form action="http://localhost:8080/test/Login" method="post"> 用户:<input type="text" name="username"/><br/> 密码:<input type="password" name="password"/><br/&

黑马程序员---java基础-Java类 继承&amp;抽象&amp;接口

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.继承 继承是所有OOP语言不可缺少的部分,在java中使用extends关键字来表示继承关系.当创建一个类时,总是在继承,如果没有明确指出要继承的类,就总是隐式地从根类Object进行继承.比如下面这段代码: 1 class Person { 2 public Person() { 3 4 } 5 } 6 class Man extends Person { 7 public Man()

Javascript:原型模式类继承

原型模式 每个函数(准确说不是类.对象)都有一个prototype属性,这个属性是一个指针,指向一个对象. 使用原型对象的好处是可以让所有对象实例共享它包含的属性和方法. 1.原型对象 (1)当创建一个新函数,就会为该函数创建一个prototype属性,这个属性指向函数的原型对象. (2)默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向 prototype属性所在函数  的指针. (3)实例的内部包含一个指针,叫[[Prototype]].不过

【深入理解JVM】:Java类继承关系中的初始化顺序

Java类初始化的顺序经常让人犯迷糊,现在本文尝试着从JVM的角度,对Java非继承和继承关系中类的初始化顺序进行试验,尝试给出JVM角度的解释. 非继承关系中的初始化顺序 对于非继承关系,主类InitialOrderWithoutExtend中包含了静态成员变量(类变量)SampleClass 类的一个实例,普通成员变量SampleClass 类的2个实例(在程序中的顺序不一样)以及一个静态代码块,其中静态代码块中如果静态成员变量sam不为空,则改变sam的引用.main()方法中创建了2个主

Java类继承关系中的初始化顺序

Java类初始化的顺序经常让人犯迷糊,现在本文尝试着从JVM的角度,对Java非继承和继承关系中类的初始化顺序进行试验,尝试给出JVM角度的解释. 非继承关系中的初始化顺序 对于非继承关系,主类InitialOrderWithoutExtend中包含了静态成员变量(类变量)SampleClass 类的一个实例,普通成员变量SampleClass 类的2个实例(在程序中的顺序不一样)以及一个静态代码块,其中静态代码块中如果静态成员变量sam不为空,则改变sam的引用.main()方法中创建了2个主

java 类继承,父类子类方法调用的过程d

1.Mytank类继承tank,则Mytank里面的公有部分即public 成员和方法在Mytank中是含有的可以调用和赋值,且在MyTank中不要有新的成员变量与tank中的公有成员名称一样,这样会发生调用紊乱,如: Tank tank = new MyTank(); int c = tank.a; 若 tank类中public a= 3: Mytank子类中新定义public a = 2: 则上述代码中的调用将会使得c = 3: 用了父类中的a.

java 类继承,父类子类方法调用的过程

1.Mytank类继承tank,则Mytank里面的公有部分即public 成员和方法在Mytank中是含有的可以调用和赋值,且在MyTank中不要有新的成员变量与tank中的公有成员名称一样,这样会发生调用紊乱,如: Tank tank = new MyTank(); int c = tank.a; 若 tank类中public a= 3: Mytank子类中新定义public a = 2: 则上述代码中的调用将会使得c = 3: 用了父类中的a.