Dojo学习笔记(三):类化JavaScript

dojo/_base/declare模块是Dojo Toolkit中创建类的基础。declare支持多重继承,这使得开发者能够编写更加灵活的代码并避免代码多次重写。Dojo.Dijit和Dojox模块都使用declare,在这篇文章中,你就知道为什么你也要这样做了。

准备学习

在开始学习这篇文章前,请确保你复习过 模块定义 这篇文章了。

Dojo类的基本创建

declare函数是在dojo/_base/declare模块中定义的,函数接受三个参数:className,superClass和properties。

ClassName

className参数代表要创建类的名称和命名空间。命名的类都放置在全局作用域内,className也可以通过命名空间代表继承链。

命名类:

// Create a new class named "mynamespace.MyClass"
declare("mynamespace.MyClass", null, {
 
    // Custom properties and methods here
 
});

命名类mynamespace.MyClass现在可以在应用的全局范围内使用了。

类只有在要被Dojo parser使用的情况下才能被命名,其他的类可以忽略className这一参数。

匿名类

// Create a scoped, anonymous class
var MyClass = declare(null, {
 
    // Custom properties and methods here
 
});

myClass现在就可以在作用域内被使用了。

SuperClass(es)

SuperClass参数值可以为空,可以是一个类,也可以使类的集合。如果一个新类继承至多个类,那么类集合中的第一个类是基础模型,剩下的类都是混合类。

不继承的类

var MyClass = declare(null, {
 
    // Custom properties and methods here
 
});

null代表这个类不继承至任何类。

一个类继承自另一个类

var MySubClass = declare(MyClass, {
 
    // MySubClass now has all of MyClass's properties and methods
    // These properties and methods override parent's
 
});

新的类MySubClass将继承MyClass的属性和方法。稍后我们讨论如何通过第三个参数来重写父类的属性或方法。

继承自多个类

var MyMultiSubClass = declare([
    MySubClass,
    MyOtherClass,
    MyMixinClass
],{
 
    // MyMultiSubClass now has all of the properties and methods from:
    // MySubClass, MyOtherClass, and MyMixinClass
 
});

一个类数组就代表类是多重继承,父类的属性和方法将继承给子类,类数组的第一个类作为子类的基础模板,其他的类将混合进去。

如果一个属性或方法在多个父类中出现,那么子类将继承最后一个类的属性或方法。

属性和方法对象

declare的最后一个参数是一个对象,这个对象的作用是在新类中重写父类的同名属性或同名方法。

自定义属性和方法

// Class with custom properties and methods
var MyClass = declare(MyParentClass, {
    // Any property
    myProperty1: 12,
    // Another
    myOtherProperty: "Hello",
    // A method
    myMethod: function(){
 
        // Perform any functionality here
 
        return result;
    }
});

举例:类的创建和继承

以下的代码创建了一个窗口小部件并继承自dijit/form/Button:

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);
        }
    });
});

从以上的代码片段可以得出结论:

  1. 类名叫mynamespace.Button
  2. 这个类可以在全局作用域内,通过mynamespace.Button或者模块的返回值被调用。
  3. 这个类继承自dijit/form/Button。
  4. 这个类自定义了一些属性和方法。

接下来让我们通过构造函数来深入学习类的创建。

构造函数

  类中最特殊的函数之一就是构造函数。当类初始化时,构造函数就会被触发并在新的对象中运行。这就意味着this关键字指向的是新的实例,而不是原来的类。构造函数也可以接受一些初始化参数。

// Create a new class
var Twitter = declare(null, {
    // The default username
    username: "defaultUser",
 
    // The constructor
    constructor: function(args){
        declare.safeMixin(this,args);
    }
});

  创建一个实例

var myInstance = new Twitter();

  在初始化实例的时候如果不指定username,那么实例将采用"defaultUser"作为实例名。为了使用safeMixin的方法,传入一个username参数:

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

  现在新的实例就用sitepen作为username了。

继承

  如上所述,继承就是新的实例将复制declare的第二个参数中的父类的属性和方法,如下所示:

// Define class A
var A = declare(null, {
    // A few properties...
    propertyA: "Yes",
    propertyB: 2
});
 
// Define class B
var B = declare(A, {
    // A few properties...
    propertyA: "Maybe",
    propertyB: 1,
    propertyC: true
});
 
// Define class C
var C = declare([mynamespace.A, mynamespace.B], {
    // A few properties...
    propertyA: "No",
    propertyB: 99,
    propertyD: false
});

类的新实例的属性如下:

// Create an instance
var instance = new C();
 
// instance.propertyA = "No" // overridden by B, then by C
// instance.propertyB = 99 // overridden by B, then by C
// instance.propertyC = true // kept from B
// instance.propertyD = false // created by C

  设置和重写数字,字符串和布尔型变量是线性的。在使用数组和对象的时候就要留意它们的作用域。在return中定义的数组或对象会被所有对象的实例所共享。在构造函数中定义的数组和对象就只是各个实例所拥有的了。可以参考 dojo/_base/declare 获取更多相关的信息。

this.inherited

  尽管完全重写方法是很有用的,但有时候一个继承链上的每个构造函数都会运行以保护它原始的功能。这时候就是this.inherited(argumengs)申明出场的时候了。this.inherited(argumengs)申明会调用父类中同名方法。如下所示:

// Define class A
var A = declare(null, {
    myMethod: function(){
        console.log("Hello!");
    }
});
 
// Define class B
var B = declare(A, {
    myMethod: function(){
        // Call A's myMethod
        this.inherited(arguments); // arguments provided to A's myMethod
        console.log("World!");
    }
});
 
// Create an instance of B
var myB = new B();
myB.myMethod();
 
 
// Would output:
//      Hello!
//      World!

  this.inherited方法可以任何时候在子类的代码中调用。有时候你需要在子类中函数的中间或尾部调用inherited(),还有,你不能再构造函数中调用它。

结论

  在Dojo Toolkit中declare函数式是创建模块化和可重用类的关键。declare允许通过多个类和对个属性方法来实现类的多重继承。可喜的是,declaer是很容易学习的,它允许开发者避免重复写同样的代码。

dojo/_base/declare

  想要进一步学习declare和类的创建?那就查看下面的资源:

  1. dojo.declare
  2. dojo.mixin Reference Guide
  3. Writing Your Own Widget

本系列文章翻译至Dojo官网,旨在学习Dojo并提高英语阅读能力,有翻译错误的地方请多指正!谢谢

原文地址:https://www.cnblogs.com/ruowind/p/2892055.html