javascript中Require调用js的实例

 无组织的函数们

在我最初开始写 JavaScript 函数时,通常是这样的:

 代码如下

function fun1() {
  // some code here
}
function fun2() {
  // some other code here
}
...

函数全写在全局环境中,项目很小时,通常不会有什么冲突问题。

但代码多了后,渐渐就发现,函数名称(英文词汇)有点不够用了。于是引入命名空间的概念,开始模块化代码。
命名空间下的函数

在命名空间下,我的代码这样写:

 代码如下

var com = com || {};
com.zfanw = com.zfanw || {};
com.zfanw.module1 = (function() {
  // some code here
  return {
    func1: func1,
    ...
  };
}());
com.zfanw.module2 = (function() {
  // some other code here
  return {
    func1: func1,
    ...
  };
}());
...

本着要面向对象的原则,执行函数通常我要这么写的:

com.zfanw.module1.func1.apply({},['arg1',arg2]);
...

当然,为了少打些字符,我还会在闭包中导入1公共 API 接口:www.45it.com

 代码如下

(function($, mod1) {
  // some code here
  mod1.func1.apply({},['arg1',arg2]);
}(jQuery, com.zfanw.module1));
...

至此,代码冲突的可能性已经很小,但代码依赖的问题,多脚本文件管理、阻塞的问题,渐渐浮出水面 – 命名空间的办法开始捉急。

于是 Require.js2 出场。
Require.js

首先了解下 require.js 里模块的概念3:

    A module is different from a traditional script file in that it defines a well-scoped object that avoids polluting the global namespace. It can explicitly list its dependencies and get a handle on those dependencies without needing to refer to global objects, but instead receive the dependencies as arguments to the function that defines the module.

简单地说,有两点,一、模块作用域自成一体,不污染全局空间;二、模块指明依赖关系,并且依赖是通过参数传递的形式导入的,无需通过全局对象引用 – 依赖同样不污染全局空间。
定义模块

与上面的老长的命名空间方式不同,require.js 用全局方法 define 来定义模块,形式如下:

 代码如下

define(id?, dependencies?, factory); // ? 表示可选项

我且把模块分两种。
无依赖的模块

假如一个模块并不依赖其他模块,那么定义起来是很简单的,比如模块 hello 放在 hello.js 文件中:

 代码如下

define(function() {
  // some code here
  return {
    // some public api
  };
});

有依赖的模块

有依赖的模块要稍稍复杂点,define 时,我们需要罗列出模块的依赖情况:

 代码如下

define(['jquery'], function($) { // 比如这个模块,代码的执行依赖 jQuery,require.js 会先加载 jquery 模块代码,并加以执行,然后将依赖模块 以 $ 的参数形式传入回调函数中,回调函数将执行结果注册为模块
  // maybe some code here
  return {
    // some public api
  };
});

这里,依赖中的 'jquery' 是模块相对于 baseUrl 的路径,等效于模块 ID。

现在,再回过头,看看上面写过的闭包中导入公共 API 的代码,跟 define 函数做个对比:

 代码如下

(function($, mod1) {
  // some code here
  mod1.func1.apply({},['arg1',arg2]);
}(jQuery, com.zfanw.module1));

这段代码里,我同样把 jQuery 导入了,在闭包里,我同样是通过 $ 这个外部传入的参数来访问 jQuery。可以说,它「定义依赖」的方式跟 define 方法很相似,不同的是,define 导入的 jquery 不是全局变量,所以不会污染全局环境。
关于模块名称

define 函数有三个参数,第一个 id 即模块名称,这个名称的格式是相对于 baseUrl 的路径除去文件格式,比如 baseUrl 为 js 目录,一个模块放在 js/libs/hi.js 里,则如果名称是这样定义的:

 代码如下

define('libs/hi', ['jquery'], function($){......});

这样的定义形式的好处是,模块不可能冲突,因为同一目录下不允许同名文件。但也因此 require.js 建议我们不要设置模块名称,因为设置了 ‘libs/hi’ 的模块名称后,模块就必须放在 js/libs 目录下的 hi.js 文件中,要移动位置的话,模块名称要跟着改变。至于后期利用 r.js 优化时生成了模块名称,那已经是另外一回事。
使用模块

在定义好「有依赖」、「没依赖」的各种模块后,我们该怎么用它?Require.js 提供了一个函数,require(与 requirejs 等效)。

require 函数加载依赖并执行回调,与 define 不同的是,它不会把回调结果4注册成模块:

 代码如下

require(['jquery'], function($) { // 这个函数加载 jquery 依赖,然后执行回调代码
  console.log($);
});

举一个简单的例子。我有一个文件夹,文件结构如下:

 代码如下

    index.html
    js/
        main.js
        require.js
        jquery.js

这里 jquery.js 已经注册为 AMD 模块,则 HTML 文件里这样引用 require.js:

 代码如下

<script src="js/require.js" data-main="js/main"></script>

require.js 会检查 data-main 属性值,这里是 js/main,根据设定,它会加载 js 目录下的 main.js 文件。

main.js 文件里,我只干一件事,用 jQuery 方法取得当前窗口的宽度:

 代码如下

require(['jquery'], function($) {
    var w = $(window).width();
    console.log(w);
});

执行代码就这么简单。
非 AMD 规范的模块

但事情远没有我们想像中那么美好,AMD 只是一种社区规范,并非标准,而且在它出现以前,已经有各种各样的流行库存在,更不用说我们自己早期写的代码,所以我们一定会碰上一堆非 AMD 规范的模块。为了让 require.js 能够加载它们,并且自动识别、载入依赖,我们有两种选择,一、给它们全穿上一个叫 define 的函数;二、使用 Require.js 提供的配置选项 shim,曲线救国。

比如我手上一个项目,因为某种原因,还在用 jQuery 1.4.1 版本,而 jQuery 是从1.7版本开始才注册为 AMD 模块的,我要在 require.js 中使用,就需要先做 shim:

 代码如下

require.config({
    shim: {
        'jquery-1.4.1': { // <= 这个是相对于 main.js 的路径www.45it.com
            exports: 'jQuery' // <= 这个值需要稍加注意,稍后会提及
        },
        'libs/jquery-throttle-debounce.min': { // <= jQuery 插件
            deps: ['jquery-1.4.1'] //无需 exports,因为我们只是在增强 jQuery 功能
        }
    },
});
require(['jquery-1.4.1', 'libs/jquery-throttle-debounce.min'], function($){
    console.log($.debounce);
});

写完 shim,发现 jquery-1.4.1、libs/jquery-throttle-debounce.min 这样的名称有点长。这里我们又有两种选择,一是直接打开修改 js 文件名,或者使用 require.js 提供的配置项 paths 给模块 ID 指定对应的真实文件路径:

 代码如下

require.config({
    paths: {
        'jquery': 'jquery-1.4.1', // <= 模块 jquery 指向 js/jquery-1.4.1.js 文件
        'debounce': 'libs/jquery-throttle-debounce.min'
    },
    shim: {
        'jquery': {
            exports: '$'
        },
        'debounce': {
            deps: ['jquery']
        }
    }
});
require(['jquery', 'debounce'], function($){
    console.log($.debounce);
});

这样,引用起来就方便多了。

另外,需要注意 shim 中的 exports 项,它的概念更接近 imports,即把全局变量导入。我们如果把 exports 值改成非全局变量名,就会导致传入回调的对象变成 undefined,举个例子:

 代码如下

require.config({
    paths: {
        'jquery': 'jquery-1.4.1',
    },
    shim: {
        'jquery': {
            exports: 'hellojQuery' // 这里我把 exports 值设置为 jQuery/$ 以外的值
        }
    }
});
require(['jquery'], function($){
    console.log($);// 这里,会显示 undefined
});

其他模块在做 shim 时同理,比如 underscore 需要 exports 成 _。
Require.js 的好处

说了这么多,Require.js 到底有什么好处?

    并行加载

    我们知道,<script></script> 标签会阻塞页面,加载 a.js 时,后面的所有文件都得等它加载完成并执行结束后才能开始加载、执行。而 require.js 的模块可以并行下载,没有依赖关系的模块还可以并行执行,大大加快页面访问速度。

    不愁依赖

    在我们定义模块的时候,我们就已经决定好模块的依赖 – c 依赖 b,b 又依赖 a。当我想用 c 模块的功能时,我只要在 require函数的依赖里指定 c:

    require(['c'], function(c) {...});

    至于 c 依赖的模块,c 依赖的模块的依赖模块… 等等,require.js 会帮我们打理。

    而传统的 script 办法,我们必须明确指定所有依赖顺序:

 代码如下

    <script src="js/a.js"></script>
    <script src="js/b.js"></script>
    <script src="js/c.js"></script>

    换句话说,传统的 script 方法里,我们极可能要靠记忆或者检查模块内容这种方式来确定依赖 – 效率太低,还费脑。

    减少全局冲突

    通过 define 的方式,我们大量减少了全局变量,这样代码冲突的概率就极小极小 – JavaScript 界有句话说,全局变量是魔鬼,想想,我们能减少魔鬼的数量,我想是件好事。

关于全局变量

有一点需要说明的是,require.js 环境中并不是只有 define 和 require 几个全局变量。许多库都会向全局环境中暴露变量,以 jQuery 为例,1.7版本后,它虽然注册自己为 AMD 模块,但同时也向全局环境中暴露了 jQuery 与 $。所以以下代码中,虽然我们没有向回调函数传入一份引用,jQuery/$ 同样是存在的:

 代码如下

require(['jquery'], function(){
  console.log(jQuery);
  console.log($);
});

时间: 2024-09-20 16:59:09

javascript中Require调用js的实例的相关文章

javascript中Require调用js的实例说明

无组织的函数们 在我最初开始写 JavaScript 函数时,通常是这样的:  代码如下 复制代码 function fun1() {   // some code here } function fun2() {   // some other code here } ... 函数全写在全局环境中,项目很小时,通常不会有什么冲突问题. 但代码多了后,渐渐就发现,函数名称(英文词汇)有点不够用了.于是引入命名空间的概念,开始模块化代码. 命名空间下的函数 在命名空间下,我的代码这样写:  代码如

JavaScript中扩展Array contains方法实例

 这篇文章主要介绍了JavaScript中扩展Array contains方法实例,本文直接给出实现代码,需要的朋友可以参考下     javascript的Array没有contains方法,有时候这会不方便,contains方法实现很简单: 代码如下: function contains(a, obj) { var i = a.length; while (i--) { if (a[i] === obj) { return true; } } return false; } 当然我们也可以扩

php php调用js js-PHP中如何调用JS自定义函数

问题描述 PHP中如何调用JS自定义函数 大家好,小弟最近在做一个PHP页面,页面中有一个下拉列表的onchange事件需要调用一个JS文件中得方法,我试了很多次依然不能成功,请各位大神帮忙出出主意吧~!跪谢~~! 解决方案 PHP是无法直接调用JS函数的,因为不是一个层面的东西,如果你想问的是PHP与JS通信,可把数据互通 参考:PHP与Javascript通信流程深入解析 解决方案二: 这个问题啊,怎么说呢,首先得明白html和js的关系,其实js是脚本,php也是脚本,当时设计出来的初衷都

模拟javascript中的sort排序(简单实例)_javascript技巧

一.javascript中sort对数据进行排序的原理 sort() 方法对数组的元素做原地的排序,并返回这个数组. sort 可能不是稳定的.默认按照字符串的Unicode码位点排序; 语法:arr.sort([compareFunction]) 参数 compareFunction 可选.用来指定按某种顺序进行排列的函数.如果省略,元素按照转换为的字符串的诸个字符的Unicode位点进行排序. 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前: 如

对象-javascript中经常提到的【实例】是什么意思?

问题描述 javascript中经常提到的[实例]是什么意思? 经常在博客或者教程里看到 实例化,或者实例这个词 比如创建一个对象实例 这样. 但是一直不是很清楚这个实例具体是什么意思, 求解! 解决方案 就是类的实例,如果学过面向对象编程就很容易明白了 function MyClass(){} var m=new MyClass();//m就是MyClass的实例,MyClass是类,new就是创建操作符 解决方案二: 对象就是类的实例化,类是对某一类事物的描述,并不实实在在存在,而new一个

javascript中如何调用el表达式的值

问题描述 javascript中如何调用el表达式的值 解决方案 <script language="JavaScript">var userName = "${user.userName}";</script>如果是字符串类型别忘了引号~解决方案二:直接调用.解决方案三:如:${user.userName}

ios中如何调用js

问题描述 ios中如何调用js 解决方案 解决方案二: iOS不太了解,跟java应该类似吧解决方案三: 冒个泡,,打酱油中.

ThinkPHP里用U方法调用js文件实例

  本文实例讲述了ThinkPHP里用U方法调用js文件的方法.分享给大家供大家参考.具体如下: 在TP里提供了在模板文件中直接调用函数的快捷方法.U是其中之一.手册里有它的用法: 代码如下: {:U('User/insert' )} 先把js文件的后缀改成html(这个不会影响),然后写个JsAction,在里面进行调用: ? 1 2 3 4 5 6 7 8 9 <?php class JsAction extends Action{ function nav() { $this->disp

ThinkPHP里用U方法调用js文件实例_php实例

本文实例讲述了ThinkPHP里用U方法调用js文件的方法.分享给大家供大家参考.具体如下: 在TP里提供了在模板文件中直接调用函数的快捷方法.U是其中之一.手册里有它的用法: 复制代码 代码如下: {:U('User/insert' )} 先把js文件的后缀改成html(这个不会影响),然后写个JsAction,在里面进行调用: <?php class JsAction extends Action{ function nav() { $this->display('Index:js:nav