《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)


相关推荐

  • 为什么说hashmap是线程不安全的_map线程不安全

    为什么说hashmap是线程不安全的_map线程不安全 hashMap线程不安全的原因及表现hashMap出现线程不安全的原因:HashMap的实现里没有锁的机制,因此它是线程不安全的。其实只要有锁的机制,可以通过锁实现线程安全,我们在读写HashMap对象的时候加锁,以保障这个对象的线程安全,但不代表HashMap本身是线程安全的,因为是外力(你自己加的锁)使然。为啥不在HashMap内部加锁让它变成线程安全?这…

  • HttpClient详细使用示例「建议收藏」

    HttpClient详细使用示例「建议收藏」HTTP协议可能是现在Internet上使用得最多、最重要的协议了,越来越多的Java应用程序需要直接通过HTTP协议来访问网络资源。虽然在JDK的javanet包中已经提供了访问HTTP协议的基本功能,但是对于大部分应用程序来说,JDK库本身提供的功能还不够丰富和灵活。HttpClient是ApacheJakartaCommon下的子项目,用…

  • java excel转json

    java excel转jsonpackagecom.xmg.excel;importjava.io.BufferedWriter;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.OutputStreamWriter;importjava.net.URL;import…

  • linux下tomcat8安装详解(附图解步骤)

    linux下tomcat8安装详解(附图解步骤)Linux下Tomcat8的安装配置安装tomcat前首先要安装对应的jdk并配置Java环境。一、环境准备jdk版本:1.8工具:xShell5xftp5说明:本文是通过Xshell5工具远程连接Linux操作,原理一样.二、安装步骤1、下载安装包官网下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downlo…

  • Vue(5)计算属性computed

    Vue(5)计算属性computed前言一般情况下属性都是放到data中的,但是有些属性可能是需要经过一些逻辑计算后才能得出来,那么我们可以把这类属性变成计算属性。比如以下:<divid="example&quot

  • mysql卸载重装教程_MySQL安装不了

    mysql卸载重装教程_MySQL安装不了关于MySQL的安装和卸载,需要的小伙伴可以参考下

发表回复

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

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