Maison > Article > interface Web > Copie profonde d'objets en JavaScript
Qu'est-ce que le développement modulaire ?
Dans le développement front-end, au début, certains effets interactifs de base pouvaient être obtenus en intégrant des dizaines ou des centaines de lignes de code dans des balises de script. Plus tard, js a attiré l'attention et est devenu largement utilisé, notamment jQuery, Ajax, et Node.Js , MVC, MVVM, etc. ont également attiré l'attention sur le développement front-end et rendu les projets front-end de plus en plus complexes. Cependant, JavaScript ne fournit aucune aide évidente pour organiser le code, et il n'y en a même pas. le concept de classes, sans parler de modules, alors qu'est-ce qu'un module ?
Un module est un fichier qui implémente une fonction spécifique. Avec un module, nous pouvons utiliser le code d'autres personnes plus facilement et charger le module de notre choix pour la fonction de notre choix. Le développement des modules doit suivre certaines normes, sinon tout sera gâché.
Selon les spécifications AMD, nous pouvons utiliser Defin pour définir des modules et exiger l'appel de modules.
Actuellement, il existe deux principaux types de spécifications de module js : CommonJS et AMD.
Spécification AMD
AMD est une définition de module asynchrone, et le nom chinois signifie « définition de module asynchrone ». Il s'agit d'une spécification pour le développement modulaire côté navigateur. La spécification côté serveur est que les modules CommonJS
seront chargés de manière asynchrone et que le chargement des modules n'affectera pas l'exécution des instructions suivantes. Toutes les instructions qui dépendent de certains modules sont placées dans des fonctions de rappel.
AMD est la sortie standardisée des définitions de modules pendant le processus de promotion de RequireJS.
Fonction define()
La spécification AMD ne définit qu'une seule fonction de définition, qui est une variable globale. La description de la fonction est :
define(id?, dependencies?, factory);
Description du paramètre :
id : fait référence au nom du module dans la définition, facultatif ; s'il n'est pas fourni Pour ce paramètre, le nom du module doit être par défaut le nom du script spécifié demandé par le chargeur de module. Si ce paramètre est fourni, le nom du module doit être "de niveau supérieur" et absolu (les noms relatifs ne sont pas autorisés).
Dépendances : il s'agit d'un littéral de tableau dont dépend le module actuel et qui est identifié par le module défini par le module.
Le paramètre de dépendance est facultatif, si ce paramètre est omis, il doit être par défaut ["require", "exports", "module"]. Cependant, si l'attribut length de la méthode factory est inférieur à 3, le chargeur choisira d'appeler la méthode factory avec le nombre d'arguments spécifié par l'attribut length de la fonction.
Factory méthode factory, le module initialise la fonction ou l'objet à exécuter. S'il s'agit d'une fonction, elle ne doit être exécutée qu'une seule fois. S'il s'agit d'un objet, cet objet doit être la valeur de sortie du module.
Format du nom du module
Le nom du module est utilisé pour identifier de manière unique le module dans la définition. Ils sont également utilisés dans le tableau de dépendances :
Le nom du module est séparé par forward. barres obliques Une chaîne de mots significatifs
Le mot doit être en casse chameau, ou ".", ".."
Le nom du module n'autorise pas les extensions de fichier, telles que ".js"
Le nom du module peut être « Relatif » ou « niveau supérieur ». Si le premier caractère est "." ou "..", il s'agit d'un nom de module relatif
Le nom du module de niveau supérieur est résolu à partir du module conceptuel de l'espace de noms racine
Le nom du module relatif est résolu à partir du "require" module écrit et appelé
Créez un module nommé "alpha" en utilisant require et exports
, en utilisant require, exports et un module nommé "beta":
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //Or: return require("beta").verb(); } });
nécessite une introduction à l'API : https://github.com/amdjs/amdjs-api/wiki/require
Spécification AMD version chinoise : https:// /github.com/amdjs/amdjs-api/wiki/AMD-(version chinoise)
Actuellement, les bibliothèques qui implémentent AMD incluent RequireJS, curl, Dojo, Nodules, etc.
Spécification CommonJS
CommonJS est une spécification pour les modules côté serveur, et Node.js adopte cette spécification. Node.JS a d'abord adopté le concept de modularité js.
Selon la spécification CommonJS, un seul fichier est un module. Chaque module a une portée distincte, c'est-à-dire que les variables définies dans le module ne peuvent pas être lues par d'autres modules à moins qu'elles ne soient définies comme attributs de l'objet global.
La meilleure façon d'exporter des variables de module est d'utiliser l'objet module.exports.
var i = 1; var max = 30; module.exports = function () { for (i -= 1; i++ < max; ) { console.log(i); } max *= 1.1; };
Le code ci-dessus définit une fonction via l'objet module.exports, qui est le pont entre la communication externe et interne du module.
Le chargement des modules utilise la méthode require, qui lit un fichier et l'exécute, et renvoie enfin l'objet module.exports à l'intérieur du fichier.
Spécification CommonJS : http://javascript.ruanyifeng.com/nodejs/commonjs.html
RequireJS et SeaJS
RequireJS a été créé par James Burke, qui est également le Fondateur de la spécification AMD. La méthode
define est utilisée pour définir les modules. RequireJS nécessite que chaque module soit placé dans un fichier séparé.
RequireJS et Sea.js sont tous deux des chargeurs de modules, prônant le concept de développement modulaire, et leur valeur fondamentale est de rendre le développement modulaire de JavaScript simple et naturel.
La plus grande différence entre SeaJS et RequireJS :
L'attitude de SeaJS envers les modules est une exécution paresseuse, tandis que l'attitude de RequireJS envers les modules est la pré-exécution
Vous ne comprenez pas ? Jetez un œil à cet article avec images et textes : http://www.douban.com/note/283566440/
API RequireJS : http://www.requirejs.cn/docs/api.html
Utilisation de RequireJS : http://www.ruanyifeng.com/blog/2012/11/require_js.html
Pourquoi utiliser requireJS
试想一下,如果一个网页有很多的js文件,那么浏览器在下载该页面的时候会先加载js文件,从而停止了网页的渲染,如果文件越多,浏览器可能失去响应。其次,要保证js文件的依赖性,依赖性最大的模块(文件)要放在最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。
RequireJS就是为了解决这两个问题而诞生的:
(1)实现js文件的异步加载,避免网页失去响应;
(2)管理模块之间的依赖性,便于代码的编写和维护。
RequireJS文件下载:http://www.requirejs.cn/docs/download.html
AMD和CMD
CMD(Common Module Definition) 通用模块定义。该规范明确了模块的基本书写格式和基本交互规则。该规范是在国内发展出来的。AMD是依赖关系前置,CMD是按需加载。
在 CMD 规范中,一个模块就是一个文件。代码的书写格式如下:
define(factory);
factory 为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:require、exports 和 module:
define(function(require, exports, module) { // 模块代码 });
require是可以把其他模块导入进来的一个参数,而export是可以把模块内的一些属性和方法导出的。
CMD规范地址:https://github.com/seajs/seajs/issues/242
AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。
AMD:提前执行(异步加载:依赖先执行)+延迟执行
CMD:延迟执行(运行到需加载,根据顺序执行)
CMD 推崇依赖就近,AMD 推崇依赖前置。看如下代码:
// CMD define(function(require, exports, module) { var a = require('./a') a.doSomething() // 此处略去 100 行 var b = require('./b') // 依赖可以就近书写 b.doSomething() // ... }) // AMD 默认推荐的是 define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好 a.doSomething() // 此处略去 100 行 b.doSomething() ... })
另外一个区别是:
AMD:API根据使用范围有区别,但使用同一个api接口
CMD:每个API的职责单一
AMD的优点是:异步并行加载,在AMD的规范下,同时异步加载是不会产生错误的。
CMD的机制则不同,这种加载方式会产生错误,如果能规范化模块内容形式,也可以
jquery1.7以上版本会自动模块化,支持AMD模式:主要是使用define函数,sea.js虽然是CommonJS规范,但却使用了define来定义模块
所以jQuery已经自动模块化了
seajs.config({ 'base':'/', 'alias':{ 'jquery':'jquery.js'//定义jQuery文件 } });
define函数和AMD的define类似:
define(function(require, exports, module{ //先要载入jQuery的模块 var $ = require('jquery'); //然后将jQuery对象传给插件模块 require('./cookie')($); //开始使用 $.cookie方法 });
sea.js如何使用?
引入sea.js的库
如何变成模块?
define
3.如何调用模块?
-exports
-sea.js.use
4.如何依赖模块?
-require
<script type="text/javascript"> define(function (require,exports,module) { //exports : 对外的接口 //requires : 依赖的接口 require('./test.js');//如果地址是一个模块的话,那么require的返回值就是模块中的exports }) </script>
sea.js 开发实例
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>鼠标拖拽的模块化开发实践</title> <style type="text/css"> #div1{ width:200px; height:200px; background:black; position:absolute; display:none;} #div2{ width:30px; height:30px; background:yellow; position:absolute; bottom:0; right:0;} #div3{ width:100px; height:100px; background:blue; position:absolute; right:0; top:0;} </style> <script type="text/javascript" src="./sea.js"></script> <script type="text/javascript"> //A同事 : seajs.use('./main.js'); </script> </head> <body> <input type="button" value="确定" id="input1" /> <div id="div1"> <div id="div2"></div> </div> <div id="div3"></div> </body> </html>
A同事
//A同事写的main.js: define(function (require,exports,module) { var oInput = document.getElementById('input1'); var oDiv1 = document.getElementById('div1'); var oDiv2 = document.getElementById('div2'); var oDiv3 = document.getElementById('div3'); require('./drag.js').drag(oDiv3); oInput.onclick = function () { oDiv1.style.display = 'block'; require('./scale.js').scale(oDiv1,oDiv2); require.async('./scale.js', function (ex) { ex.scale(oDiv1,oDiv2); }) } });
B同事
//B同事写的drag.js: define(function(require,exports,module){ function drag(obj){ var disX = 0; var disY = 0; obj.onmousedown = function(ev){ var ev = ev || window.event; disX = ev.clientX - obj.offsetLeft; disY = ev.clientY - obj.offsetTop; document.onmousemove = function(ev){ var ev = ev || window.event; var L = require('./range.js').range(ev.clientX - disX , document.documentElement.clientWidth - obj.offsetWidth , 0 ); var T = require('./range.js').range(ev.clientY - disY , document.documentElement.clientHeight - obj.offsetHeight , 0 ); obj.style.left = L + 'px'; obj.style.top = T + 'px'; }; document.onmouseup = function(){ document.onmousemove = null; document.onmouseup = null; }; return false; }; } exports.drag = drag;//对外提供接口 });
C同事
//C同事写的scale.js: define(function(require,exports,module){ function scale(obj1,obj2){ var disX = 0; var disY = 0; var disW = 0; var disH = 0; obj2.onmousedown = function(ev){ var ev = ev || window.event; disX = ev.clientX; disY = ev.clientY; disW = obj1.offsetWidth; disH = obj1.offsetHeight; document.onmousemove = function(ev){ var ev = ev || window.event; var W = require('./range.js').range(ev.clientX - disX + disW , 500 , 100); var H = require('./range.js').range(ev.clientY - disY + disH , 500 , 100); obj1.style.width = W + 'px'; obj1.style.height = H + 'px'; }; document.onmouseup = function(){ document.onmousemove = null; document.onmouseup = null; }; return false; }; } exports.scale = scale; });
D同事
// D同事的range.js--限定拖拽范围 define(function(require,exports,module){ function range(iNum,iMax,iMin){ if( iNum > iMax ){ return iMax; } else if( iNum < iMin ){ return iMin; } else{ return iNum; } } exports.range = range; });
requirejs开发实例
require.config是用来定义别名的,在paths属性下配置别名。然后通过requirejs(参数一,参数二);参数一是数组,传入我们需要引用的模块名,第二个参数是个回调函数,回调函数传入一个变量,代替刚才所引入的模块。
main.js文件
//别名配置 requirejs.config({ paths: { jquery: 'jquery.min' //可以省略.js } }); //引入模块,用变量$表示jquery模块 requirejs(['jquery'], function ($) { $('body').css('background-color','red'); });
引入模块也可以只写require()。requirejs通过define()定义模块,定义的参数上同。在此模块内的方法和变量外部是无法访问的,只有通过return返回才行.
define 模块
define(['jquery'], function ($) {//引入jQuery模块 return { add: function(x,y){ return x + y; } }; });
将该模块命名为math.js保存。
main.js引入模块方法
require(['jquery','math'], function ($,math) { console.log(math.add(10,100));//110 });
没有依赖
如果定义的模块不依赖其他模块,则可以:
define(function () { return { name: "trigkit4", age: "21" } });
AMD推荐的风格通过返回一个对象做为模块对象,CommonJS的风格通过对module.exports或exports的属性赋值来达到暴露模块对象的目的。
更多JavaScript 中对象的深拷贝相关文章请关注PHP中文网!