1、JavaScript 继承方式

(1)对象冒充

在 JavaScript 中,构造函数也和普通的函数一样,可以被赋值和调用,对象冒充通过此原理来模拟继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta charset="UTF-8">
    <title>declare</title>
</head>
<body>
    <script type="text/javascript">
        function ClassA(name)
        {
            this.name = name;
            this.sayHello = function(){
                alert("Hello, " +  this.name);
            }
        }
        function ClassB(name,time)
        {
            this.newMethod = ClassA;
            this.newMethod(name);
            delete this.newMethod;
            this.time = time;
            this.sayGoodbye = function(){
                alert("Goodbye " this.name + ",it's " this.time + " now !");
            }
        }
        var objA = new ClassA("Tom");
        var objB = new ClassB("Jerry","11:30am");
        console.log("开始执行-------")
        objA.sayHello();// output is : "Hello,Tom"
        objB.sayHello(); // output is : "Hello,Jerry"
        objB.sayGoodbye();// output is : "Goodbye Jerry, it ’ s 11:30am now!"
    </script>
</body>
</html>

将 ClassA 的构造函数赋值为 ClassB 的一个普通方法,然后调用它,由于此时 this 指向的是 ClassB 的实例,那么 ClassB 的实例就会收到 ClassA 构造函数中定义的属性和方法,从而达到了继承的效果。

需要注意的是,应及时删除临时引用(this.newMethod),以防止 ClassB 更改 ClassA 类对象的引用。因为对临时引用(this.newMethod)的更改,也会导致 ClassA 的结构变化。并且 ClassB 的所有新属性和新方法,应该在删除临时引用后定义,否则,可能会覆盖父类的相关属性和方法。

可以采用 JavaScript 中的 call 或者 apply 函数达到同样的效果。

(2)基于原型的继承

JavaScript 中的每个对象都包含一个原型对象(prototype),指向对某个对象的引用,而由于原型对象本身也是对象,则也会包含对它的原型的引用,由此构成一条原型链。原型链终止于内建 Object 类的原型。当要读取某个对象的属性或方法时,JavaScript 首先在该对象中查找,若没有找到,便在该对象的原型中继续查找,若仍未找到,便顺着原型链继续在原型的原型中查找,直到查找到或到达原型链的尽头。这样的系统被称为原型继承。而基于原型的继承,则是指利用了 prototype 或者说以某种方式覆盖了 prototype,从而达到属性及方法复用的目的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta charset="UTF-8">
    <title>declare</title>
</head>
<body>
    <script type="text/javascript">
        function ClassA()
        {
            this.name = "";
            this.sayHello = function(){
                alert("Hello, " +  this.name);
            }
        }
        function ClassB(){};
        ClassB.prototype = new ClassA();
        var objB = new ClassB();
        objB.name = "Jerry";
        objB.sayHello(); //output: "Hello,Jerry";
    </script>
</body>
</html>

(3)混合方式继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta charset="UTF-8">
    <title>declare</title>
</head>
<body>
    <script type="text/javascript">
        function ClassA(name){
            this.name = name;
        }
        ClassA.prototype.sayHello = function(){
            alert("Hello, " +  this.name);
        }
        function ClassB(name,time){
            ClassA.call(this, name);
            this.time = time;
        }
        ClassB.prototype = new ClassA();
        ClassB.prototype.sayGoodbye = function(){
            alert("Goodbye " this.name + ",it's " this.time + " now !");
        }
        var objA = new  ClassA("Tom");
        var objB = new  ClassB("Jerry","11:30am");
        objA.sayHello();// output is: "Hello, Tom"
        objB.sayHello(); // output is: "Hello, Jerry"
        objB.sayGoodbye();//output is: "Goodbye Jerry,it ’ s 11:30am now !"
    </script>
</body>
</html>

2、dojo.declare

dojo.declare可以声明一个类,而不污染继承的类。

语法:

    dojo.declare(/*String*/  className,  /*Function | Function[]*/ superclass,  /*Object*/ props)

参数说明:

 className: 是要要申明的类的类名,也就是创建的构造函数的名称,可忽略。

superclass:所要继承的父类,此参数可为 null,表示没有父类。

 props:类体,包括类的属性和方法,由名、值(key, value)对组成,其中constructor 为保留字,此函数用来初始化新对象。

(1)命名类

1
2
3
4
5
6
// Create a new class named "mynamespace.MyClass"
declare("mynamespace.MyClass"null, {
  
    // Custom properties and methods here
  
 });

    现在在应用程序中,一个叫 mynamespace.MyClass 的类已经全局可用了。一般来说只有需要通过 Dojo parser 解析时才定义命名类。其他情况下,我们定义的类一般都忽略 className 参数。

(2)匿名类

1
2
3
4
5
6
// Create a scoped, anonymous class
var MyClass = declare(null, {
  
    // Custom properties and methods here
  
});

现在 MyClass 类仅在给定空间中有效。

(3)定义无继承的类

1
2
3
4
5
var MyClass = declare(null, {
  
    // Custom properties and methods here
  
});

(4)定义从已有类继承的类

1
2
3
4
5
6
var MySubClass = declare(MyClass, {
     
    // MySubClass 类现在拥有 MyClass 类的所有属性和方法
    // 父类的属性和方法可以被重载
  
});

新的 MySubClass 类会继承 MyClass 类的所有属性和方法。父类方法或属性(key:新值)可以被重载。

(5)定义从多个类继承的类

1
2
3
4
5
6
7
8
9
10
var MyMultiSubClass = declare([
    MySubClass,
    MyOtherClass,
    MyMixinClass
],{
  
    // MyMultiSubClass 现在拥有以下类的所有属性和方法::
    // MySubClass, MyOtherClass, and MyMixinClass
  
});

这个数组就表明是从多个类继承。属性和方法会按照父类从左到右进行继承。 数组列表中的第一个类将提供基础原型(base prototype),其他的类则会被混入到新类中。

 如果父类具有相同的属性或者方法,则最后一个父类的属性或方法会被采纳。

样例:

--Basic Class 的创建和继承

1
2
3
4
5
6
7
8
9
10
11
12
define([
    "dojo/_base/declare",
    "dijit/form/Button"
], function(declare, Button){
    return declare("mynamespace.Button", Button, {
        label"My Button",
        onClick: function(evt){
            console.log("I was clicked!");
            this.inherited(arguments);
        }
    });
});

上面代码创建一个继承自 dijit/form/Button 的小部件 (widget):

(1)类名是 mynamespace.Button;

(2)可通过全局类名 mynamespace.Button 引用,可以通过模块返回值引用;

(3)类继承自: dijit/form/Button (以及 Button's 的依赖关系);

(4)类中自定义了一些属性和方法。

(6)构造函数constructor

constructor在类派生实例对象时触发,随后在该对象的作用域执行。因此 this 关键字是指向对象实例,而非类。constructor 方法可以接受任意长度参数,用于实例初始化。

1
2
3
4
5
6
7
8
9
10
// Create a new class
var Twitter = declare(null, {
    // The default username
    username: "defaultUser",
  
    // The constructor
    constructor: function(args){
        declare.safeMixin(this,args);
    }
});

创建一个实例对象:

  

1
  var  myInstance = new  Twitter();

这里没有指定 username,缺省值为 "defaultUser" 。To leverage the safeMixin method, 我们可以提供 username 参数

   

1
2
3
 var myInstance = new Twitter({
        username: "sitepen"
    });

declare.safeMixin 用在类的创建和继承中,是用于创建具有不定参数的类的好帮手。

(7)继承Inheritance

继承关系是通过 declare 的第二个参数定义的。如果某个属性或方法已存在,则子类会按照父类参数,从左至右进行替换混入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta charset="UTF-8">
    <title>declare</title>
    <script type="text/javascript" src="dojo/dojo.js" data-dojo-config="async:true"></script>
</head>
<body>
    <script type="text/javascript">
        require(["dojo/_base/declare"],function(declare){
            // 定义类 A
            var A = declare(null, {
                // A few properties...
                propertyA: "Yes",
                propertyB: 2,
                add : function(a1){
                    return a1;
                }
            });
            // 定义类 B
            var B = declare(A, {
                // A few properties...
                propertyA: "Maybe",
                propertyB: 1,
                propertyC: true,
                add : function(a1,a2){
                    return a1+a2;
                }
            });
            // 定义类 C
            var C = declare([A, B], {
                // A few properties...
                propertyA: "No",
                propertyB: 99,
                propertyD: false,
                objectVal: [123]
            });
            // 创建实例
            var instance = new C();
            console.log("propertyA值:"+instance.propertyA);
            console.log("propertyB值:"+instance.propertyB);
            console.log("propertyC值:"+instance.propertyC);
            console.log("propertyD值:"+instance.propertyD);
            console.log("add方法:"+instance.add(10,20));
            console.log("objectVal值:"+instance.objectVal);
            instance.propertyA="YES";
            instance.objectVal.push(5);
            var instance1=new C();
            console.log("另一个实例propertyA值:"+instance1.propertyA);
            console.log("另一个实例objectVal值:"+instance1.objectVal);
        });
    </script>
</body>
</html>

输出结果:

"propertyA值:No" declare.html:43

"propertyB值:99" declare.html:44

"propertyC值:true" declare.html:45

"propertyD值:false" declare.html:46

"add方法:30" declare.html:47

"objectVal值:1,2,3" declare.html:48

"另一个实例propertyA值:No" declare.html:52

"另一个实例objectVal值:1,2,3,5"

当我们从一个实例对象读取一个属性时,首先是查找实例对象本身是否包含这个属性如果没有,则遍历原型链,直到找到原型链中第一个包含该属性的对象,并返回该值。如果给实例对象的某个属性(可能是继承来的)赋值(基础数据类型,例如:number, string, boolean等),则该值只会保存在实例对象上,而非原型上。但是,如果你给原型的某个属性赋的是个 object values (Object, Array),那么所有实例对象访问的就是同一个共享值了

为了避免不小心在实例间共享了数组或对象,对象属性一般赋为 null,然后在构造函数中进行初始化。(注:构造函数是在实例对象的空间中运行了,因此他赋的值只对该实例对象有效)。

1
2
3
4
5
6
7
8
9
10
11
12
13
declare(null, {
    // 非强制要求,但出于代码可读性考虑
    // 最好将所有属性声明放在这里
    memberList: null,
    roomMap: null,
  
    constructor: function () {
        // 在构造器中初始化所有属性,确保数据就绪,便于其他方法使用
        // 并且不要赋null 值或 undefined
        this.memberList = [];
        this.roomMap = {};
    }
});

(8)回调父类同名方法this.inherited

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta charset="UTF-8">
    <title>declare</title>
    <script type="text/javascript" src="dojo/dojo.js" data-dojo-config="async:true"></script>
</head>
<body>
    <script type="text/javascript">
        require(["dojo/_base/declare"],function(declare){
            // 定义类 A
            var A = declare(null, {
                myMethod: function(){
                    console.log("Hello");
                }
            });
            // 定义类 B
            var B = declare(A, {
                myMethod: function(name){
                    // 调用类A的myMethod方法
                    // 类A的myMethod方法提供的参数arguments
                    this.inherited(arguments);
                    console.log(name);
                }
            });
            // 创建类B的实例
            var myB = new B();
            myB.myMethod("world");
        });
    </script>
</body>
</html>

输出结果:

"Hello"

"world"

 注意:不要在 constructor 中调用this.inherited。

参考文献:1、http://dojotoolkit.org/documentation/tutorials/1.10/declare/

2、http://www.ibm.com/developerworks/cn/web/1203_xiejj_dojodeclare/

     本文转自stock0991 51CTO博客,原文链接:http://blog.51cto.com/qing0991/1400857,如需转载请自行联系原作者

Dojo学习笔记(六):dojo/_base/declare相关推荐

  1. Dojo学习笔记(8. dojo.event dojo.event.topic dojo.event.browser)

    Dojo学习笔记(8. dojo.event & dojo.event.topic & dojo.event.browser) 模块:dojo.event 终于进入有名的dojo事件处 ...

  2. Dojo学习笔记(7. dojo.dom)

    Dojo学习笔记(7. dojo.dom) 模块:dojo.dom dojo.dom.isNode 测试指定对象是否为节点 Usage Example: dojo.dom.isNode(dojo.by ...

  3. dojo 学习笔记之dojo.query - query(id) 与query(class)的差别

    考虑这个样例:动态创建一个页面的时候,用new listtem()生成多个listitem, 且每一个listitem中都生成一个按钮button. 假设想要给每一个按钮都绑定一个click事件,用d ...

  4. Polyworks脚本开发学习笔记(六)-比较运算、数学运算、逻辑运算及流程控制

    Polyworks脚本开发学习笔记(六)-比较运算.数学运算.逻辑运算及流程控制 前言 比较运算.逻辑运算及流程控制是编程的基本语法,Polyworks的语法规则与VB/C#/Python等并没有很大 ...

  5. Ethernet/IP 学习笔记六

    Ethernet/IP 学习笔记六 EtherNet/IP defines two primary types of communications: explicit and implicit (Ta ...

  6. 吴恩达《机器学习》学习笔记六——过拟合与正则化

    吴恩达<机器学习>学习笔记六--过拟合与正则化 一. 过拟合问题 1.线性回归过拟合问题 2.逻辑回归过拟合问题 3.过拟合的解决 二. 正则化后的代价函数 1.正则化思想 2.实际使用的 ...

  7. ROS学习笔记六:理解ROS服务和参数

    ROS学习笔记六:理解ROS服务和参数 主要介绍ROS服务和参数,同时使用命令行工具rosservice和rosparam. ROS service service是节点之间互相通信的另一种方式,se ...

  8. opencv 手选roi区域_【opencv学习笔记六】图像的ROI区域选择与复制

    图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...

  9. JS学习笔记六:js中的DOM操作

    1. JS学习笔记六:js中的DOM操作 文章目录 1. JS学习笔记六:js中的DOM操作 1.1. 获取Dom节点 1.2. 元素属性的操作方式 1.3. DOM节点的创建.插入和删除 1.4. ...

  10. Python学习笔记六——画小猪佩奇

    目录 Python学习笔记六--画小猪佩奇 画布 画笔 属性设置 操纵命令 运动命令 画笔控制命令 全局控制命令 其他命令 Python学习笔记六--画小猪佩奇 使用Python的turtle库可以绘 ...

最新文章

  1. php获取图高度,PHP imagesx()、imagesy() – 获取图像宽度与高度_程序员人生
  2. 【深度学习】陶大程等人编写!最新41页深度学习理论综述
  3. 【BZOJ1452】[JSOI2009]Count(树状数组)
  4. [单选题]PDO::ATTR_ERRMODE设置为以下哪个值时,PDO会抛出PDOException?
  5. 小程序 、h5图片铺满div,自适应容器大小
  6. asm 5 java,java – 使用ASM(5.x)在字节代码中检测运行时的递归方法调用:howto?
  7. 【Java】《基于Java的面向对象范式》学习笔记分享
  8. numpy 加速 矩阵相加_Numpy知识
  9. Predicate函数式接口
  10. linux 科学绘图软件,在Linux中使用matplotlib进行科学画图
  11. http地址后面加上问号?防止IE缓存
  12. uva225 回溯剪枝
  13. Holy Grail
  14. Ubuntu如何把主文件夹的中文设置成英文
  15. 用震盘实现中性笔这一大类笔的笔帽的定向上料设计(SolidWorks模型讲解)
  16. Machine Learning - Coursera 吴恩达机器学习教程 Week1 学习笔记
  17. 白盒测试——NextDate函数测试(基本路径覆盖法)
  18. Nervos CKB初体验
  19. python3里复数的算法,Python 3复数
  20. [网赚项目] 抖音小程序变现流程详细拆解

热门文章

  1. 数据预处理代码分享——机器学习与数据挖掘
  2. Spring使用环境变量控制配置文件加载(转)
  3. MongoDB学习(五)使用Java驱动程序3.3操作MongoDB快速入门
  4. Servlet 2.0 Servlet 3.0 新特性
  5. 变量声明和定义的区别
  6. Atitit.安全性方案规划设计4gm  v1 q928
  7. Android SystemProperties设置/取得系统属性的用法总结
  8. com学习笔记(6)类厂
  9. 生活问题 | 对华为畅玩手机5X进行升级
  10. Python中fnmatch模块的使用