首頁 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

熱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

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

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

如何使用PHP和webpack進行模組化開發 如何使用PHP和webpack進行模組化開發 May 11, 2023 pm 03:52 PM

隨著Web開發技術的不斷發展,前後端分離、模組化開發已成為了廣泛的趨勢。 PHP作為一種常用的後端語言,在進行模組化開發時,我們需要使用一些工具來實現模組的管理和打包,其中webpack是一個非常好用的模組化打包工具。本文將介紹如何使用PHP和webpack進行模組化開發。一、什麼是模組化開發模組化開發是指將程式分解成不同的獨立模組,每個模組都有自己的作

PHP學習筆記:模組化開發與程式碼重複使用 PHP學習筆記:模組化開發與程式碼重複使用 Oct 10, 2023 pm 12:58 PM

PHP學習筆記:模組化開發與程式碼重複使用引言:在軟體開發中,模組化開發與程式碼重複使用是相當重要的概念。模組化開發可以將複雜的系統分解成可管理的小模組,提高開發效率和程式碼可維護性;而程式碼重複使用則可以減少冗餘程式碼,提高程式碼的重用性。在PHP開發中,我們可以透過一些技術手段來實現模組化開發和程式碼重複使用。本篇文章將介紹一些常用的技術和具體程式碼範例,幫助讀者更好地理解和應用這些概

C++開發建議:如何進行模組化的C++開發 C++開發建議:如何進行模組化的C++開發 Nov 23, 2023 am 08:56 AM

C++語言作為一種通用的高階程式語言,被廣泛用於開發各種應用程式和系統。然而,C++的複雜性和靈活性也使得開發人員面臨一些挑戰,特別是在大型專案中。在處理大型專案時,模組化的開發方法是至關重要的。本文將介紹如何進行模組化的C++開發,並提供一些建議和最佳實務。模組化開發是指將一個大型專案劃分為多個小模組,每個模組有自己的功能和職責,透過模組間的介面進行通信

ThinkPHP6模組化開發:拆解應用邏輯 ThinkPHP6模組化開發:拆解應用邏輯 Aug 12, 2023 am 10:53 AM

ThinkPHP6模組化開發:拆解應用邏輯隨著網路的快速發展,Web應用開發也變得越來越複雜。一個龐大的應用可能包含了多個模組,每個模組負責不同的功能,拆解應用邏輯成為一個必須考慮的問題。本文將介紹如何在ThinkPHP6中實現模組化開發,並透過程式碼範例來幫助讀者理解。一、創建模組在ThinkPHP6中,模組是應用功能上的劃分,可以根據實際需求來創建不同的

Python腳本在Linux系統中實作模組化開發的技術指南 Python腳本在Linux系統中實作模組化開發的技術指南 Oct 05, 2023 am 11:53 AM

Python腳本在Linux系統中實現模組化開發的技術指南引言:Python是一種簡單易學且功能強大的高階程式語言,廣泛應用於不同領域的開發。在Linux系統中,Python腳本的模組化開發可以有效提高程式碼的可維護性和重複使用性,降低開發和維護成本。本文將介紹如何在Linux系統中使用Python實現模組化開發的技術指南,並提供具體的程式碼範例。一、模組化開

Vue開發建議:如何進行模組化開發和元件重複使用 Vue開發建議:如何進行模組化開發和元件重複使用 Nov 22, 2023 am 09:51 AM

Vue是一款流行的JavaScript框架,用於建立使用者介面。它採用了組件化的開發方式,使得開發者可以輕鬆地進行模組化開發和組件復用。本文將介紹一些關於如何進行模組化開發和組件重複使用的Vue開發建議。一、模組化開發模組化開發是一種將複雜的系統拆解成若干獨立的模組,每個模組負責完成特定的功能。在Vue中,我們可以使用Vue組件來實現模組化開發。下面是一些關於模組

微服務架構下如何實現PHP功能的模組化開發? 微服務架構下如何實現PHP功能的模組化開發? Sep 18, 2023 pm 01:31 PM

微服務架構下如何實現PHP功能的模組化開發?隨著技術的不斷發展,微服務架構在軟體開發中變得越來越受歡迎。它將一個大型的應用程式拆分成許多小的、獨立的功能模組,每個模組都可以獨立進行開發、部署和擴展。對於PHP開發者來說,如何使用微服務架構實現功能的模組化開發是一個重要的議題。在本文中,我們將介紹一些在微服務架構下實現PHP功能模組化開發的技術和最佳實務。首先

Spring Boot的模組化開發與應用場景 Spring Boot的模組化開發與應用場景 Jun 23, 2023 am 09:16 AM

當我們談到SpringBoot時,我們通常會想到一個快速開發的框架。但是,它的好處並不僅限於這些。 SpringBoot的另一個很棒的功能是它支援模組化開發,這使得開發更加輕鬆,更容易維護。在本文中,我們將探討SpringBoot模組化開發的基礎知識和如何在實際應用中使用該特性。什麼是SpringBoot模組? SpringBoot模組是一組功能相

See all articles