1. 在HTML
页面中,通过<scritp>
签加载JavaScript
脚本, 有两种方式:内嵌
和外部引用
-
内嵌
将脚本内容直接置于<scritp>
签的内容中 -
外部引用
通过<scritp>
签的src
属性引用一个脚本文件
推荐采用
外部引用
方式:
- 便于维护
采用内嵌的方式,会使JS
脚本遍布各个页面中,而引用脚本文件的话,可以把JS
脚本集中放到一个文件夹中,方便管理,程序员在不触碰HTML
页的情况下,集中精力开发JS
脚本。 -
JS
脚本可在多个页面中共享和缓存, 最终可以加快页面加载速度。
2. <scritp>
签, 可置于页面的<head>
或 <body>
部分
- 最早
<scritp>
和<link>
签一样, 统一放在<head>
部分
但是,这样做有明显的缺点, 这会导致JS
立即下载并顺序执行,很有可能阻塞页面渲染。
HTML5
规范,特意引入defer
和async
属性 实现外部引用
的脚本延迟执行,区别是defer
保证脚本按顺序执行,async
并不保证。 - 推荐放在
<body>
的尾部 一定会在页面渲染完成后,下载并执行。
3. JavaScript
模块化
JavaScript
没有名字空间的概念,当加载多个 JS
脚本时,特别是引入第三方脚本时, 很容易产生名字污染,所以一般不会直接在JS
的全局域中直接定义函数和变量,而是定义一个模块对象,包含这些函数和变量。
// common.js 传统写法,全局域中直接定义函数和变量 很容易造成名字污染
var DATA_PATH = '/data/source/';
var someInternalState = true;
function doSth() {
//...
}
// 定义一个模块对象,包含这些导出的函数和变量
var common = {
DATA_PATH : '/data/source/',
someInternalState : true,
doSth : function () {
//...
}
}
// 进一步改进, 采用`立即执行函数`的办法,只暴露接口,隐藏实现细节 ,比如实例中的someInternalState
var common = function () {
var DATA_PATH = '/data/source/';
var someInternalState = true;
function doSth() {
...
}
return {
DATA_PATH : DATA_PATH ,
doSth : doSth
}
}
4. 目前 最流行的方式 是通过RequrieJS
来 异步加载JS
脚本。
RequireJS
传统方式加载
JS
脚本, 都是同步、顺序的执行,同步可能导致阻塞问题, 顺序执行需要当心 脚本间依赖关系, 不得不 手动指定<script>
签顺序,依赖最少的排在最前面,而且当JS
脚本越来越多时,<scritp>
签会越来越多,页面也会显得臃肿、丑陋
是什么 ?
是一个JavaSript
库,帮助我们完成脚本的模块化(符合AMD
规范), 实现异步加载。
怎么用?
- 页面: 在
<body>
尾部添加一条<script>
签
<!-- src指定 RequireJS位置, data-main指定主模块位置 -->
<script src='require.js' data-main='main.js' > </script>
- 主模块 使用
require
函数 导入其他模块。主模块的作用类似main函数,是程序的入口点
// 假设主模块main.js依赖于 requery.js 和 common.js,在默认情况下, RequireJS会从主模块目录查找依赖模块
// require第一个参数是依赖的模块名列表, 模块名不能指定.js后缀; 第二个参数,是依赖模块全都加载完毕后的回调函数,传入依赖模块的导出结果。
require(['jquery', 'common'], function($, common) {
// ....
});
// 当依赖模块和主模块不在一个目录下时,需要额外的配置 baseUrl 属性
// 特别注意的是,baseUrl支持相对和绝对路径, 示例以/开头,是一个本地的绝对路径;如果忽略开头的/,则是一个相对于主模块所在路径的相对路径
require.config({
baseUrl"/js/others"
});
require(['jquery', 'common'], function($, common) {
// ....
});
// 当依赖模块并不都在一个目录时,需要单独的配置paths属性(特别是需要引用外网的JS脚本时)
require.config({
baseUrl"/js/others"
paths: {
"jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"// 完整的Url
}
});
require(['jquery', 'common'], function($, common) {
// ....
});
- 依赖模块 使用
define
函数 符合AMD
规范// 没有额外依赖时 传入一个返回模块对象的匿名函数 define(function() { // ... 最终返回导出对象 return { functions, variables }; }); // 有额外依赖时,第一个参数是依赖模块名的列表
define([‘base’], function(base) {
//… 最终返回导出对象
return { functions, variables };
} );
4. 当依赖模块不符合`AMD`规范时,直接改造或者在导入时配置 shim 属性
```javascript
// 依赖模块 common.js
function a() {
//...
}
function b() {
//...
}
//主模块 main.js 需要导入common.js的一个名字时,配置exports属性
require.config({
shim : {
'common' : {
deps : ['jquery'] , // common依赖的模块名
exports : ' a' // 需要导出的函数或者变量名字
}
}
});
// 需要导入多个名字时,配置init属性
require.config({
shim : {
'common' : {
deps : ['jquery'] , // common依赖的模块名
init: function() {
return {
a:a,
b:b
}
}
}
}
});
5. 值得期待的是 ,ES6标准 引入了class
和module
概念,规范了脚本模块化和加载方式,但浏览器完全支持尚需时日。
本篇文章总结了在前端浏览器中如何使用JavaScript
,有三种方式,传统的<script>
签, 流行的 RequireJS
插件,以及面向未来的 ES6。接下来,我要总结后台Node.js环境中,如何使用JavaScript
脚本。