《JavaScript 模式》读书笔记(5)— 对象创建模式1「建议收藏」

这又是一个新的开始,对象的重要性不言而喻。在JavaScript中创建对象是十分容易的,之前聊过的对象字面量和构造函数都可以达到目的。但是本篇中,我们越过那些方法,以寻求一些额外的对象创建模式。本篇

大家好,又见面了,我是你们的朋友全栈君。

  这又是一个新的开始,对象的重要性不言而喻。在JavaScript中创建对象是十分容易的,之前聊过的对象字面量和构造函数都可以达到目的。但是本篇中,我们越过那些方法,以寻求一些额外的对象创建模式。

  本篇内容,我们将学到命名空间(namespace),依赖声明(dependency declaration)、模块模式(module pattern)、沙箱模式(sandbox pattern)。它们都可以帮助您组织应用程序代码的结构,并且降低隐含的全局变量带来的后果。其他讨论的主题包括私有和特权成员、对象常量、链和一个启发类的方式以以定义构造函数。

 

一、命名空间模式

  命名空间(namespace)有助于减少程序中所需要的全局变量的数量,并且同时还有助于避免命名冲突或过长的名字前缀。

  JavaScript语言的语法中并没有内置命名空间,但是这种特征是非常容易实现的。可以为应用程序或库创建一个(理想上最好只有一个)全局对象,然后可以将所有功能添加到该全局对象中,从而在有大量函数、对象和其他变量的情况下并不会污染全局范围。

// 5个全局变量
// 警告:反模式
// 构造函数
function Parent() {}
function Child() {}

// 一个变量
var some_var = 1;

// 一些对象
var module1 = {};
module1.data = {a:1,b:2};
var module2 = {};

// 可以通过为应用程序创建一个全局对象这种方式来重构上面这种类型的代码:
// 之后:1个全局变量
// 全局变量
var MYAPP = {};

// 构造函数
MYAPP.Parent = function () {};
MYAPP.Child = function () {};

// 一个变量
MYAPP.some_var = 1;

// 一个对象容器
MYAPP.modules = {};

// 嵌套对象
MYAPP.modules.module1 = {};
MYAPP.modules.module1.data = {a:1,b:2};
MYAPP.modules.module2 = {};

  对于全局命名空间对象的名称,可以任意选择,比如以应用程序或库的名称、域名或公司名来命名。通常根据公约,以全部大写的方式来命名全局变量,这样比较显眼(当然,常量也是这样)。

  这种模式是一种组织代码的命名空间的好方法,不仅可以避免您代码中的命名冲突,并且还可以避免在同一个页面中您的代码和第三方代码之间的命名冲突。

  当然,这样的方式也有一些缺点:

  • 需要输入更多的字符,每个变量和函数前都要附加前缀,总体上增加了需要下载的代码量。
  • 仅有一个全局实例意味着任何部分的代码都可以修改该全局实例。
  • 长嵌套名字意味着更长(更慢)的属性解析查询时间。

  本篇后面介绍的沙箱模式可以解决以上这些缺点。

 

通用命名空间函数

  由于程序负责性的增加、代码的某些部分被分割成不同的文件,以及使用条件包含语句等多个因素,仅假设您的代码是第一个定义某个命名空间或它内部的属性,这种做法已经变得不再安全。添加到命名空间的一些属性可能已经存在,这导致可能会覆盖它们。因此,在添加一个属性或者创建一个命名空间之前,最好是首先检查它是否已经存在:

// 不安全的代码
var MYAPP = {};
// 更好的代码风格
if(typeof MYAPP === 'undefined') {
    var MYAPP = {};
}
// 或者用更短的语句
var MYAPP = MYAPP || {};

  可以看到这些附加的检查是如何循序导致大量的重复代码。比如,如果想要定义MYAPP.modules.module2,必须构造三次检查,每次检查都要针对定义的一个对象或者属性。这也就是为什么需要一个可以很方便地处理命名空间细节的可重用函数的原因。让我们称该函数为namespace()并以如下方式使用:

// 使用命名空间函数
MYAPP.namespace('MYAPP.modules.module2');

// 相当于以下代码
var MYAPP = {
    modules:{
        module2:{}
    }
};

  接下来是一个命名空间函数的示例。这个实现是非破坏性的,也就是说,如果已经存在一个命名空间,便不会再重新创建它:

var MYAPP = MYAPP || {};

MYAPP.namespace = function (ns_string) {
    var parts = ns_string.split('.'),
        parent = MYAPP,
        i;

    // 剥离最前面的冗余全局变量
    if(parts[0] === "MYAPP"){
        parts = parts.slice(1);
    }

    for(i = 0;i < parts.length; i += 1){
        // 如果不存在就创建一个属性
        if(typeof parent[parts[i]] === 'undefined'){
            parent[parts[i]] = {};
        }
        parent = parent[parts[i]];
    }
    return parent;
}
// 本实现使下列所有这些用法都能正常运行:
// 将返回值赋给一个全局变量
var module2 = MYAPP.namespace('MYAPP.modules.module2');
console.log(module2 === MYAPP.modules.module2);

// 忽略最前面的‘MYAPP’
console.log(MYAPP.namespace('modules.module51'));

// 长命名空间
console.log(MYAPP.namespace('once.upon.a.time.there.was.this.long.short.nested.property'));

 

二、声明依赖关系

  JavaScript库通常是模块化且依据命名空间组织的,这使您能够仅包含所需的模块。例如,在YUI2库中有一个充当命名空间的全局变量YAHOO,而模块是该全局变量的属性,比如YAHOO.util.Dom和YAHOO.util.Event。

  在您的函数或模块顶部声明代码所依赖的模块是一个非常好的主意。该声明仅涉及创建一个局部变量并使其指向所需的模块。

var myFunction = function () {
    // 依赖
    var event = YAHOO.util.Event,
        dom = YAHOO.util.Dom;
    
    // 使用事件和DOM变量
    // 其他逻辑
};

  这是一个及其简单的模式,但是它却有很多优点:

  • 显式的依赖声明向您代码的用户表明了他们确定需要的特定脚本文件已经包含在该页面中。
  • 在函数顶部的前期声明可以使您很容易地发现并解析依赖。
  • 解析局部变量的速度总是要比解析全局变量要快,甚至比使用全局变量的嵌套属性还要快,这导致了更好的性能。当使用这种依赖声明模式时,全局符号解析仅会在函数中执行一次。在此之后将会使用局部变量,这种解析速度也快很多。
  • 类似于YUICompressor和Google闭包编译器的这些高级小工具可以重命名局部变量(即,压缩),这导致了更小的代码量,但是这些工具从不会对全局变量进行重命名,因为这样做是不安全的。

  

  这篇就到这里了,说实话就是很小的两个点,但是这两个point,确实会给你的代码带来不错的性能提升。好了,下篇文章见。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/124388.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • LeetCode解题汇总目录

    此篇为学习完《数据结构与算法之美》后,在LeetCode刷题的汇总目录,方便大家查找(Ctrl+Find),一起刷题,一起PK交流!另有解题:《剑指Offer》、《程序员面试金典》、LintCode代码能力测试CAT。如果本文对你有帮助,可以给我点赞加油!通过2021,简单618/636,中等1120/1266,困难283/488

  • Iocomp .NET WinForms OPC Crack「建议收藏」

    Iocomp .NET WinForms OPC Crack「建议收藏」Iocomp.NETWinFormsOPC包Iocomp.NETWinFormsOPCPack是一款独立产品,可将OPC功能添加到任何.NET控件。Ω578867473它还包括连接到Iocomp.NETWinForm控件上的复杂属性的高级功能。所有许可证购买都包括1年支持和维护。支持32位和64位Window操作系统。内置自定义属性编辑器,便于设置。100%托管代码与所有.NET语言兼容。所有属性、方法和事件的完整代码示例Io

  • VB程序设计教程(第四版)龚沛曾-实验8-6「建议收藏」

    VB程序设计教程(第四版)龚沛曾-实验8-6「建议收藏」实验8-6VB程序题:编写一个随机文件程序。要求:(1)建立一个具有5个学生的学号、姓名和成绩的随机文件(Random.dat)。(2)读出Random.dat文件中的内容,然后按成绩排序,最后按顺序写入另一个随机文件(Randoml.dat)。(3)再一次读出文件的内容,按文件中的顺序将学生的信息显示在屏幕上,检查正确性。解题,画3个按钮控件,代码如下:PrivateTy…

  • PHP实现打印出库单,有没有实现过?

    PHP实现打印出库单,有没有实现过?

    2021年10月28日
  • 嵌入式和pc的区别_嵌入式系统基础教程第2版

    嵌入式和pc的区别_嵌入式系统基础教程第2版Atitit嵌入式系统与pc系统的对比目录1.哈佛结构和冯诺依曼结构普林斯顿结构区12.中断程序类库调用13.指令集三大流程语句与运算语句赋值语句14.异常处理25.存储管理(内存26.安卓嵌入式26.1.Python嵌入式26.2.Java嵌入式开发27.常见软件功能区别27.1.Dbn…

  • 按位取反运算符~_c语言∧按位异或运算符

    按位取反运算符~_c语言∧按位异或运算符https://www.cnblogs.com/shy1766IT/p/6184874.html二进制数在内存中以补码的形式存储。按位取反:二进制每一位取反,0变1,1变0。~9的计算步骤:转二进制:01001计算补码:01001按位取反:10110转为原码:按位取反:11001末位加一:11010符号位为1是负数,即-10varx…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号