搜尋
首頁web前端js教程JavaScript 中物件的深拷貝

JavaScript 中物件的深拷貝

Jan 03, 2017 pm 03:49 PM
模組化開發

什麼是模組化開發?

前端開發中,起初只要在script標籤中嵌入幾十上百行程式碼就能實現一些基本的交互效果,後來js得到重視,應用也廣泛起來了,jQuery,Ajax,Node.Js,MVC,MVVM等的助力也使得前端開發得到重視,也使得前端專案越來越複雜,然而,JavaScript卻沒有為組織程式碼提供任何明顯幫助,甚至沒有類別的概念,更不用說模組(module)了,那麼什麼是模組呢?

一個模組就是實現特定功能的文件,有了模組,我們就可以更方便地使用別人的程式碼,想要什麼功能,就載入什麼模組。模組開發需要遵循一定的規範,否則就都亂了套。

根據AMD規範,我們可以使用define定義模組,使用require呼叫模組。

目前,通行的js模組規格主要有兩種:CommonJS和AMD。

AMD規範

AMD 即Asynchronous Module Definition,中文名是「非同步模組定義」的意思。它是一個在瀏覽器端模組化開發的規範,伺服器端的規範是CommonJS

模組將會被非同步加載,模組載入不影響後面語句的運作。所有依賴某些模組的語句均放置在回調函數中。

AMD 是 RequireJS 在推廣過程中對模組定義的規範化的產出。

define() 函數

AMD規格只定義了一個函數 define,它是全域變數。函數的描述為:

define(id?, dependencies?, factory);

   

參數說明:

id:指定義中模組的名字,可選;如果沒有提供該參數,模組的名字應該預設為模組載入器請求的指定腳本的名字。如果提供了該參數,模組名必須是「頂級」的和絕對的(不允許相對名字)。

依賴dependencies:是一個當前模組依賴的,已被模組定義的模組標識的數組字面量。
依賴參數是可選的,如果忽略此參數,它應該預設為["require", "exports", "module"]。然而,如果工廠方法的長度屬性小於3,載入器會選擇以函數的長度屬性指定的參數個數呼叫工廠方法。

工廠方法factory,模組初始化要執行的函數或物件。如果為函數,它應該只被執行一次。如果是對象,此對象應該為模組的輸出值。

模組名的格式

模組名用來唯一標識定義中模組,它們同樣在依賴性數組中使用:

模組名是用正斜杠分割的有意義單詞的字符串
單詞須為駝峰形式,或".",".."
模組名不允許檔案副檔名的形式,如“.js”
模組名可以為"相對的" 或"頂級的"。如果首字符為“.”或“..”則為相對的模組名
頂層的模組名從根命名空間的概念模組解析
相對的模組名從"require" 書寫和調用的模組解析

使用require和exports

創建一個名為"alpha"的模組,使用了require,exports,和名為"beta"的模組:

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

   

require API 介紹:https://githubub.com/djgithub.com/djgithub amdjs-api/wiki/require

AMD規範中文版:https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89% 88)

目前,實作AMD的函式庫有RequireJS 、curl 、Dojo 、Nodules 等。

CommonJS規範

CommonJS是伺服器端模組的規範,Node.js採用了這個規範。 Node.JS首先採用了js模組化的概念。

根據CommonJS規範,一個單獨的檔案就是一個模組。每一個模組都是一個單獨的作用域,也就是說,在該模組內部定義的變量,無法被其他模組讀取,除非定義為global物件的屬性。

輸出模組變數的最佳方法是使用module.exports物件。

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

   

上面程式碼透過module.exports對象,定義了一個函數,就是模組外在與內部通訊的橋樑。

載入模組使用require方法,該方法讀取一個檔案並執行,最後返回檔案內部的module.exports物件。

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
Python和JavaScript的未來:趨勢和預測Python和JavaScript的未來:趨勢和預測Apr 27, 2025 am 12:21 AM

Python和JavaScript的未來趨勢包括:1.Python將鞏固在科學計算和AI領域的地位,2.JavaScript將推動Web技術發展,3.跨平台開發將成為熱門,4.性能優化將是重點。兩者都將繼續在各自領域擴展應用場景,並在性能上有更多突破。

Python vs. JavaScript:開發環境和工具Python vs. JavaScript:開發環境和工具Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

JavaScript是用C編寫的嗎?檢查證據JavaScript是用C編寫的嗎?檢查證據Apr 25, 2025 am 12:15 AM

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python vs. JavaScript:比較用例和應用程序Python vs. JavaScript:比較用例和應用程序Apr 21, 2025 am 12:01 AM

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C/C在JavaScript口譯員和編譯器中的作用C/C在JavaScript口譯員和編譯器中的作用Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具