JavaScript模块模式与模块增强

2021-03-04
478
666

模块模式

模块模式是在一个单例对象基础上加以扩展,使其通过作用域链来关联私有变量和特权方法。

一个基本的模块模式样板代码:

const singleton = function () {
    // 私有变量和私有函数
    let privateVariable = 100

    return privateFunction() {
        return false
    }

    // 暴露公有方法和属性
    return {
        publicProperty: true,
        publciMethod() {
            privateVariable++
            return privateFunction()
        }
    }
}

模块模式使用了匿名函数返回一个对象。在匿名函数内部,首先定义私有变量和私有函数。之后创建一个要通过匿名函数返回的对象字面量。这个对象字面量中只包含可以公开访问的属性和方法。

因为这个对象定义在匿名函数内部,所以它的公共方法可以访问它所处作用域的所有变量和函数(尽管这些变量和函数在外部看来是私有的)。本质上,返回的对象字面量定义了单例对象的公共接口。如果单例对象需要进行某种初始化,并且需要访问私有变量时,那就可以采用下面这种模式:

let application = function () {
    // 私有变量和私有函数
    const components = new Array()

    // 初始化
    components.push(new BaseComponent())

    // 暴露公共接口
    return {
        getComponentCount() {
            return components.length
        },
        registerComponent(component) {
            if (typeof component == 'object') {
                components.push(component)
            }
        }
    }
}() // 匿名函数立即执行

在 Web 开发中,经常需要使用单例对象管理应用程序级的信息。上面这个例子创建了一个 application 对象用于管理组件。在创建这个对象之后,内部就会创建一个私有数组 components,然后将一个 BaseComponent 组件的实例 push 到该数组中。(BaseComponent 的代码并不重要,把它看作一个组件抽象类即可)。

对象字面量中定义的 getComponentCount() 和 registerComponent() 方法都是可以访问 components 私有数组的“特权方法”。前一个方法返回注册组件的数量,后者负责注册新的组件。

在模块模式中,单例对象作为一个模块,经过初始化可以包含某些私有数据,而这些数据又可以通过其暴露的公共接口来访问。以这种方式创建的每个单例对象都是 Object 的实例,因为最终单例都由一个对象字面量来表示。不过这无关紧要,因为单例对象通常是可以全局访问的,而不是作为参数传给函数的,所以可以避免使用 instanceof 操作符确定参数是不是对象类型的需求。

模块增强模式

另一个利用模块模式的做法是在返回对象之前先对其进行增强。这适合单例对象需要是某个特定类型的实例,但又必须给他它添加额外的属性或方法的场景。来看看下面的例子:

const singleton = function () {
    // 私有变量和私有函数
    const privateVariable = 100
    
    function privateFunction () {
        return false
    }

    // 创建对象
    const obj = new CustomType()

    // 添加公有方法和属性
    obj.publicProperty = true

    obj.publicMethod = function () {
        privateVariable++
        return privateFunction()
    }

    // 返回对象
    return obj
}() // 立即执行

如果说前面的 application 对象必须是 BaseComponent 的实例,那么就可以使用下面的方式来创建它:

const application = function () {
    // 私有变量和函数
    const components = new Array()

    // 初始化
    components.push(new BaseComponent())

    // 创建局部变量保存实例
    const app = new BaseComponent()

    // 把公共接口挂载到局部实例上
    app.getComponentCount = function () {
        return components.length
    }

    app.registerComponent = function (component) {
        if (typeof component == 'object') {
            components.push(component)
        }
    }

    // 返回局部实例
    return app
}() // 立即执行

在这个重写的 application 单例对象的例子中,首先定义了私有变量和私有函数,跟之前例子中一样。主要区别在于这里创建了一个名为 app 的 BaseComponent 组件的实例。这是最重要变成 application 对象的局部版本。在这个局部实例上挂载了能够访问私有变量和私有函数的公共接口,匿名函数返回这个局部对象后最终赋值给外部的 application。

478

文章版权所有:PORK's BLOG,采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。

欢迎分享,转载务必保留出处及原文链接