>  기사  >  웹 프론트엔드  >  JavaScript의 객체 전체 복사

JavaScript의 객체 전체 복사

高洛峰
高洛峰원래의
2017-01-03 15:49:031411검색

모듈 개발이란 무엇인가요?

모듈이란 특정 기능을 구현한 파일을 말하며, 모듈을 사용하면 다른 사람의 코드를 보다 편리하게 사용할 수 있고, 원하는 기능에 대해 원하는 모듈을 로드할 수 있습니다. 모듈 개발은 특정 규범을 따라야 합니다. 그렇지 않으면 모든 것이 엉망이 될 것입니다.

AMD 사양에 따라 정의를 사용하여 모듈을 정의하고 모듈을 호출하도록 요구할 수 있습니다.

현재 js 모듈 사양에는 CommonJS와 AMD의 두 가지 주요 유형이 있습니다.

AMD 사양

AMD는 비동기 모듈 정의(Asynchronous Module Definition)이며 중국어 이름은 "비동기 모듈 정의"를 의미합니다. 브라우저 측의 모듈 개발을 위한 사양입니다. 서버 측 사양은 CommonJS

모듈이 비동기적으로 로드되고 모듈 로드가 후속 명령문 실행에 영향을 미치지 않는다는 것입니다. 특정 모듈에 의존하는 모든 명령문은 콜백 함수에 배치됩니다.

AMD는 RequireJS 승격 과정에서 표준화된 모듈 정의 출력입니다.

define() 함수

AMD 사양에서는 전역 변수인 하나의 함수 정의만 정의합니다. 함수 설명은 다음과 같습니다.

define(id?, dependencies?, factory);

매개변수 설명:

id: 정의에 있는 모듈의 이름을 나타냅니다. 선택 사항입니다. 제공되지 않은 경우 이 매개 변수의 경우 모듈 이름은 기본적으로 모듈 로더가 요청한 지정된 스크립트의 이름이어야 합니다. 이 매개변수가 제공되면 모듈 이름은 "최상위"이고 절대적이어야 합니다(상대 이름은 허용되지 않음).

종속성: 현재 모듈이 의존하는 배열 리터럴이며 모듈에서 정의한 모듈로 식별됩니다.

종속성 매개변수는 선택사항입니다. 이 매개변수가 생략되면 기본값은 ["require", "exports", "module"]입니다. 그러나 팩토리 메소드의 길이 속성이 3보다 작으면 로더는 함수의 길이 속성에 지정된 개수의 인수를 사용하여 팩토리 메소드를 호출하도록 선택합니다.


팩토리 메소드 팩토리, 모듈이 실행할 함수나 객체를 초기화합니다. 함수인 경우 한 번만 실행되어야 합니다. 객체인 경우 이 객체는 모듈의 출력 값이어야 합니다.

모듈 이름 형식

모듈 이름은 정의에서 모듈을 고유하게 식별하는 데 사용됩니다. 종속성 배열에도 사용됩니다.

모듈 이름은 앞쪽으로 구분됩니다. 슬래시 의미 있는 단어의 문자열

단어는 카멜 표기법 또는 ".", ".."이어야 합니다.

모듈 이름은 ".js"와 같은 파일 확장자를 허용하지 않습니다.
모듈 이름 "상대적" 또는 "최상위 수준"일 수 있습니다. 첫 번째 문자가 "." 또는 ".."이면 상대 모듈 이름입니다.
최상위 모듈 이름은 루트 네임스페이스의 개념적 모듈에서 확인됩니다.
상대 모듈 이름은 "require" 작성 및 호출 모듈

require 및 내보내기를 사용하여 "alpha"라는 모듈 만들기

, require, 내보내기 및 "beta"라는 모듈을 사용:

define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
   exports.verb = function() {
     return beta.verb();
     //Or:
     return require("beta").verb();
   }
 });

require API 소개: https://github.com/amdjs/amdjs-api/wiki/require

AMD 사양 중국어 버전: https:/ /github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88)

현재 AMD를 구현하는 라이브러리에는 RequireJS, 컬, 그리고 Dojo, Nodules et al.

CommonJS 사양

CommonJS는 서버 측 모듈에 대한 사양으로 Node.js에서는 이 사양을 채택합니다. Node.JS는 처음으로 js 모듈성 개념을 채택했습니다.

CommonJS 사양에 따르면 단일 파일은 모듈입니다. 각 모듈에는 별도의 범위가 있습니다. 즉, 모듈 내에 정의된 변수는 전역 객체의 속성으로 정의되지 않는 한 다른 모듈에서 읽을 수 없습니다.

모듈 변수를 내보내는 가장 좋은 방법은 module.exports 개체를 사용하는 것입니다.

var i = 1;
var max = 30;
 
module.exports = function () {
 for (i -= 1; i++ < max; ) {
  console.log(i);
 }
 max *= 1.1;
};

위 코드는 모듈의 외부 통신과 내부 통신을 연결하는 역할을 하는 module.exports 객체를 통해 함수를 정의합니다.

모듈 로딩은 파일을 읽고 실행한 후 최종적으로 파일 내부의 module.exports 객체를 반환하는 require 메소드를 사용합니다.

CommonJS 사양: http://javascript.ruanyifeng.com/nodejs/commonjs.html

RequireJS 및 SeaJS

RequireJS는 James Burke에 의해 만들어졌습니다. AMD 사양 창시자.

define 메소드는 모듈을 정의하는 데 사용됩니다. RequireJS에서는 각 모듈을 별도의 파일에 배치해야 합니다.

RequireJS와 Sea.js는 모두 모듈 로더로 모듈 개발 개념을 옹호하며, 이들의 핵심 가치는 JavaScript의 모듈 개발을 간단하고 자연스럽게 만드는 것입니다.

SeaJS와 RequireJS의 가장 큰 차이점:

SeaJS의 모듈에 대한 태도는 게으른 실행인 반면, RequireJS의 모듈에 대한 태도는 사전 실행입니다

이해가 안 되시나요? 사진과 텍스트가 포함된 이 기사를 살펴보세요: http://www.douban.com/note/283566440/

RequireJS API: http://www.requirejs.cn/docs/api.html

RequireJS 사용법: http://www.ruanyifeng.com/blog/2012/11/require_js.html

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(&#39;./a&#39;)
a.doSomething()
// 此处略去 100 行
var b = require(&#39;./b&#39;) // 依赖可以就近书写
b.doSomething()
// ...
})
 
// AMD 默认推荐的是
define([&#39;./a&#39;, &#39;./b&#39;], 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({
&#39;base&#39;:&#39;/&#39;,
&#39;alias&#39;:{
  &#39;jquery&#39;:&#39;jquery.js&#39;//定义jQuery文件
}
});

   

define函数和AMD的define类似:

define(function(require, exports, module{
   //先要载入jQuery的模块
   var $ = require(&#39;jquery&#39;);
   //然后将jQuery对象传给插件模块
   require(&#39;./cookie&#39;)($);
   //开始使用 $.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(&#39;./test.js&#39;);//如果地址是一个模块的话,那么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(&#39;./main.js&#39;);
   
</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(&#39;input1&#39;);
  var oDiv1 = document.getElementById(&#39;div1&#39;);
  var oDiv2 = document.getElementById(&#39;div2&#39;);
  var oDiv3 = document.getElementById(&#39;div3&#39;);
 
  require(&#39;./drag.js&#39;).drag(oDiv3);
  oInput.onclick = function () {
    oDiv1.style.display = &#39;block&#39;;
    require(&#39;./scale.js&#39;).scale(oDiv1,oDiv2);
 
    require.async(&#39;./scale.js&#39;, 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(&#39;./range.js&#39;).range(ev.clientX - disX , document.documentElement.clientWidth - obj.offsetWidth , 0 );
         var T = require(&#39;./range.js&#39;).range(ev.clientY - disY , document.documentElement.clientHeight - obj.offsetHeight , 0 );
 
         
        obj.style.left = L + &#39;px&#39;;
        obj.style.top = T + &#39;px&#39;;
      };
      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(&#39;./range.js&#39;).range(ev.clientX - disX + disW , 500 , 100);
        var H = require(&#39;./range.js&#39;).range(ev.clientY - disY + disH , 500 , 100);
         
        obj1.style.width = W + &#39;px&#39;;
        obj1.style.height = H + &#39;px&#39;;
      };
      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: &#39;jquery.min&#39; //可以省略.js
  }
});
//引入模块,用变量$表示jquery模块
requirejs([&#39;jquery&#39;], function ($) {
  $(&#39;body&#39;).css(&#39;background-color&#39;,&#39;red&#39;);
});

   

引入模块也可以只写require()。requirejs通过define()定义模块,定义的参数上同。在此模块内的方法和变量外部是无法访问的,只有通过return返回才行.

define 模块

define([&#39;jquery&#39;], function ($) {//引入jQuery模块
  return {
    add: function(x,y){
      return x + y;
    }
  };
});

   

将该模块命名为math.js保存。

main.js引入模块方法

require([&#39;jquery&#39;,&#39;math&#39;], function ($,math) {
  console.log(math.add(10,100));//110
});

   

没有依赖

如果定义的模块不依赖其他模块,则可以:

define(function () {
 
  return {
    name: "trigkit4",
    age: "21"
  }
});

   

AMD推荐的风格通过返回一个对象做为模块对象,CommonJS的风格通过对module.exports或exports的属性赋值来达到暴露模块对象的目的。

更多JavaScript 中对象的深拷贝相关文章请关注PHP中文网!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.