摘要:應用日益復雜,模塊化已經成為一個迫切需求。異步模塊加載機制。引用的資源列表太長,懶得回調函數中寫一一對應的相關參數假定這里引用的資源有數十個,回調函數的參數必定非常多這就是傳說中的
簡述 緣起
模塊通常是指編程語言所提供的代碼組織機制,利用此機制可將程序拆解為獨立且通用的代碼單元。
模塊化主要是解決代碼分割、作用域隔離、模塊之間的依賴管理以及發布到生產環境時的自動化打包與處理等多個方面。
javascript應用日益復雜,模塊化已經成為一個迫切需求。但是作為一個模塊化方案,它至少要解決如下問題:
可維護性
避免作用域污染
代碼重用
依賴管理
script最原始的方式就是,每個文件就是一個模塊,然后使用script的方式進行引入。
但是此方式有以下問題:
全局作用域污染
無依賴管理,執行順序依賴script標簽的順序,如果采用異步加載,那會亂套,先下載的先執行
IIFE 和 模塊對象為了解決作用域污染的問題,就產生了立即執行函數 + 模塊對象模式:
// app1.js var app = {};
// app2.js (function(){ app.a = function(a, b) { // code } })();
// app3.js (function(app){ var temp = [ 1, 2]; var a = app.a(temp) })(app);
具體的可以查閱阮一峰老師的博客Javascript模塊化編程(一):模塊的寫法
在ES6之前,js沒有塊級作用域,所以采用此方式建立一個函數作用域。但是在ES6之后,可以使用塊級作用域。
由于使用了IIFE,所以減少了全局作用域污染,但并不是徹底消除,因為還定義了一個appa模塊對象呢。
所以這也僅僅只是減少了作用域污染,還是會有其他缺點。
CommonJS后來,有人試圖將javascript引入服務端,由于服務端編程相對比較復雜,就急需一種模塊化的方案,所以就誕生了commonjs,有require + module.exports實現模塊的加載和導出。
CommonJS采用同步的方式加載模塊,主要使用場景為服務端編程。因為服務器一般都是本地加載,速度較快。
AMD 和 CMD后來,隨著前端業務的日漸復雜,瀏覽器端也需要模塊化,但是commonjs是同步加載的,這意味著加載模塊時,瀏覽器會凍結,什么都干不了,這在瀏覽器肯定是不行的,這就誕生了AMD和CMD規范,分別以requirejs和seajs為代表。
這兩貨都采用異步方式加載模塊。
AMDAMD(Asynchronous Module Defination)異步模塊加載機制。
define( [module_id,] // 模塊名字,如果缺省則為匿名模塊 [dependenciesArray,] // 模塊依賴 definition function | object // 模塊內容,可以為函數或者對象 );CMD
CMD(Common Module Defination)通用模塊加載機制
// 方式一 define(function(require, exports, module) { // 模塊代碼 var a = require("a") }); // 方式二 define( "module", ["module1", "module2"], function( require, exports, module ){ // 模塊代碼 } );區別
對于依賴的模塊,AMD 是提前執行( RequireJS 從 2.0 開始,也改成可以延遲執行),CMD 是延遲執行
CMD 推崇依賴就近,AMD 推崇依賴前置
AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一
不完美盡管以上方案解決了上面說的問題,但是也帶來了一些新問題:
語法冗余,所有東西都要封裝在define中
AMD中的依賴列表必須與函數的參數列表匹配,易錯且修改苦難
Browserify由于上述這些原因,有些人想在瀏覽器使用 CommonJS 規范,但 CommonJS 語法主要是針對服務端且是同步的,所以就產生了Browserify,它是一個 模塊打包器(module bundler),可以打包commonjs規范的模塊到瀏覽器中使用。
UMDUMD(Universal Module Definition) 統一模塊定義。
AMD 與 CommonJS 雖然師出同源,但還是分道揚鑣,關注于代碼異步加載與最小化入口模塊的開發者將目光投注于 AMD;而隨著 Node.js 以及 Browserify 的流行,越來越多的開發者也接受了 CommonJS 規范。令人扼腕嘆息的是,符合 AMD 規范的模塊并不能直接運行于 CommonJS 模塊規范的環境中,符合 CommonJS 規范的模塊也不能由 AMD 進行異步加載。
而且有這么多種規范,如果我們要發布一個模塊供其他人用,我們不可能為每種規范發布一個版本,就算你蛋疼這樣做了,別人使用的時候還得下載對應版本,所以現在需要一種方案來兼容這些規范。
實現的方式就是在代碼前面做下判斷,根據不同的規范使用對應的加載方式。
// 以vue為例 (function (global, factory) { typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = global || self, global.Vue = factory()); }(this, function () { // vue code ... })
由于目前ES6瀏覽器支持還不夠好,所以很多第三方庫都采用了這種方式。
ESModuleES6引入了ESModule規范,主要通過export + import來實現,最終一統江湖。可是現實很骨感,一些瀏覽器并不支持(IE,說的就是你),所以還不能直接在瀏覽器中直接使用。
常用的兩種方案在線編譯:requirejs/seajs/sytemjs
在頁面上加載一個AMD/CMD模塊格式解釋器。這樣瀏覽器就認識了define, exports,module這些東西,也就實現了模塊化。
SystemJS 是一個通用的模塊加載器,它能在瀏覽器或者 NodeJS 上動態加載模塊,并且支持 CommonJS、AMD、全局模塊對象和 ES6 模塊。通過使用插件,它不僅可以加載 JavaScript,還可以加載 CoffeeScript 和 TypeScript。配合jspm也是不錯的搭配。
預編譯:browserify/webpack
相比于第一種方案,這個方案更加智能。由于是預編譯的,不需要在瀏覽器中加載解釋器。你在本地直接寫JS,不管是AMD/CMD/ES6風格的模塊化,它都能認識,并且編譯成瀏覽器認識的JS。
注意: browerify只支持Commonjs模塊,如需兼容AMD模塊,則需要plugin轉換
CommonJS前身為ServerJS。
我們可以理解為代碼會被如下內建輔助函數包裹:
(function (exports, require, module, __filename, __dirname) { // ... // Your code // ... });加載
通過require加載模塊。
const a = require("a")導出
通過exports和module.exports進行模塊導出。
exports:exports是module.exports的一個引用,一個模塊可以使用多次,但是不能直接對exports重新賦值,只能通過如下方式使用
exports.a = function(){ // code... }
module.exports:一個模塊只能使用一次
module.exports = function(){ // code... }特點
同步加載,定位于服務端,不適合瀏覽器
requirejs 特點支持同步和異步兩種方式
大多數第三方庫都有兼容AMD,即時不兼容也可以通過配置使其可用
異步加載,不阻塞瀏覽器
依賴前置,可以很清楚看到當前模塊的依賴
引入在引入requirejs的script標簽上添加data-main屬性定義入口文件,該文件會在requirejs加載完后立即執行。
如果baseUrl未多帶帶配置,則默認為引入require的文件的路徑。
configrequirejs.config({ // 為模塊加上query參數,解決瀏覽器緩存,只在開發環境使用 urlArgs: "yn-course=" + (new Date()).getTime(), // 配置所有模塊加載的初始路徑,所有模塊都是基于此路徑加載 baseUrl: "./", // 映射一些快捷路徑,相當于別名 paths: { "~": "assets", "@": "components", "vue": "assets/lib/vue/vue", "vueRouter": "assets/lib/vue-router/vue-router", "jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery"] }, // 對于匹配的模塊前綴,使用一個不同的模塊ID來加載該模塊 map: { "layer": { "jquery": "http://libs.baidu.com/jquery/2.0.3/jquery" } }, // 從CommonJS包(package)中加載模塊 packages:{}, // 加載上下文 context:{}, // 超時,默認7S waitSeconds: 7, // 定義應用依賴的模塊,在啟動后會加載此數組中的模塊 deps: [], // 在deps加載完畢后執行的函數 callback:function(){}, // 用來加載非AMD規范的模塊,以瀏覽器全局變量注入,此處僅作映射,需要在需要時手動載入 shim: { // "backbone": { // deps: ["underscore", "jquery"], // 模塊依賴 // exports: "Backbone" // 導出的名稱 // } }, // 全局配置信息,可在模塊中通過module.config()訪問 config:{ color:"red" }, // 如果設置為true,則當一個腳本不是通過define()定義且不具備可供檢查的shim導出字串值時,就會拋出錯誤 enforceDefine:false, // 如果設置為true,則使用document.createElementNS()去創建script元素 xhtm: false, //指定RequireJS將script標簽插入document時所用的type=""值 scriptType:"text/javascript" });
默認requirejs會根據baseUrl+paths配置去查找模塊,但是如下情況例外:
路徑以.js結尾,比如lib/hello.js、hello.js
以“/”開始
包含url協議:如"http:"、"https"
設置baseURl的方式有如下三種:
requirejs.config指定;
如指data-main,則baseUrl為data-main所對應的js的目錄
如果上述均未指定,則baseUrl為運行RequireJS的HTML文件所在目錄
map配置對于大型項目很重要:如有兩類模塊需要使用不同版本的"foo",但它們之間仍需要一定的協同。
在那些基于上下文的多版本實現中很難做到這一點。而且,paths配置僅用于為模塊ID設置root paths,而不是為了將一個模塊ID映射到另一個。
requirejs.config({ map: { "some/newmodule": { "foo": "foo1.2" }, "some/oldmodule": { "foo": "foo1.0" } } });define
通過define來定義模塊,推薦依賴前置原則,當然也可以使用require動態按需加載。
define( [module_id,] // 模塊名字,如果缺省則為匿名模塊 [dependencies,] // 模塊依賴 definition function | object // 模塊內容,可以為函數或者對象 );
// 如果僅僅返回一個鍵值對,可以采用如下格式,類似JSONP define({ color: "black", size: "unisize" }) //如果沒有依賴 define(function () { return { color: "black", size: "unisize" } }) // 有依賴 define(["./a", "./b"], function(a, b) { }) // 具名模塊 define("name", ["c", "d"], function(cart, inventory) { //此處定義foo/title object } )
如要在define()內部使用諸如require("./a/b")相對路徑,記得將"require"本身作為一個依賴注入到模塊中:
define(["require", "./a/b"], function(require) { var mod = require("./a/b"); });
或者使用如下方式:
define(function(require) { var mod = require("./a/b"); })標識
require加載的所有模塊都是單例的,每個模塊都有一個唯一的標識,這個標識是模塊的名字或者模塊的相對路徑(如匿名模塊)。
模塊的唯一性與它們的訪問路徑無關,即使是地址完全相同的一份JS文件,如果引用的方式與模塊的配置方式不一致,依舊會產生多個模塊。
// User.js define([], function() { return { username : "yiifaa", age : 20 }; });
require(["user/User"], function(user) { // 修改了User模塊的內容 user.username = "yiifee"; // em/User以baseUrl定義的模塊進行訪問 // "user/User"以path定義的模塊進行訪問 require(["em/User", "user/User"], function(u1, u2) { // 輸出的結果完全不相同,u1為yiifaa,u2為修改后的內容yiifee console.log(u1, u2); }) })依賴
requirejs推薦依賴前置,在define或者require模塊的時候,可以將需要依賴的模塊作為第一個參數,以數組的方式聲明,然后在回調函數中,依賴會以參數的形式注入到該函數上,參數列表需要和依賴數組中位置一一對應。
define(["./a", "./b"], function(a, b) { })導出
在requirejs中,有3中方式進行模塊導出:
通過return方式導出,優先級最高(推薦);
define(function(require, exports, module) { return { a : "a" } });
通關module.exports對象賦值導出,優先級次之;
define(function(require, exports, module) { module.exports = { a : "a" } });
通過exports對象賦值導出,優先級最低;
define(function(require, exports, module) { exports.a = "a" });require
requirejs提供了兩個全局變量require、requirejs供我們加載模塊,這二者是完全等價的。
// 此處require 和 define 函數僅僅是一個參數(模塊標識)的差異, // 一般require用于沒有返回的模塊,如應用頂層模塊 require( [dependencies,] // 模塊依賴 definition function // 模塊內容 );
require是內置模塊,不用在配置中定義,直接進行引用即可。
define(["require"], function(require) { var $ = require("jquery"); })
requirejs支持異步(require([module]))和同步(require(module))兩種方式加載,即require參數為數組即為異步加載,反之為同步。
同步加載在requirejs中,執行同步加載必須滿足兩點要求:
必須在定義模塊時使用,亦即define函數中;
引用的資源必須是之前異步加載過的(不必在同一個模塊),換句話說,同步載入的模塊是不會發網絡請求的,只會調取之前緩存的模塊;
define(function(require, exports, module) { })中可以同步加載模塊
應用場景明確知道模塊的先后順序,確認此模塊已經被加載過,例如系統通用模塊,在載入完成后,之后的模塊就可以進行同步的引用,或者在Vue等前端技術框架中,在應用模塊同步加載vue模塊。
引用的資源列表太長,懶得回調函數中寫一一對應的相關參數
// 假定這里引用的資源有數十個,回調函數的參數必定非常多 define(["jquery"], function() { return function(el) { // 這就是傳說中的同步調用 var $ = require("jquery"); $(el).html("Hello, World!"); } })
可以減少命名或者命名空間沖突,例如prototype與jquery的沖突問題
define(["jquery", "prototype"], function() { var export = {}; export.jquery = function(el) { // 這就是傳說中的同步調用 var $ = require("jquery"); $(el).html("Hello, World!"); } export.proto = function(el) { // 這就是傳說中的同步調用 var $ = require("prototype"); $(el).html("Hello, World!"); } return export; })
處女座專用,代碼顯得更整潔漂亮了,硬是把回調函數寫出了同步的感覺
異步加載define([],function()):依賴數組中的模塊會異步加載,所有模塊加載完成后混執行回調函數
require([]):傳入數組格式即表示需要異步加載
require === requirejs //=> truerequire.toUrl("./a.css"): 獲取模塊url 模塊卸載
只要頁面不刷新,被requirejs加載的模塊只會執行一次,后面會一直緩存在內存中,即時重新引入模塊也不會再進行初始化。
我們可以通過undef卸載已加載的模塊。
require.undef("moduleName") // moduleName是模塊標識其他 插件
css:加載css
text:加載HTML及其他文本
domReady
模塊加載錯誤Module name has not been loaded yet for context: _:
此錯誤表示執行時模塊還未加載成功,一般為異步加載所致,改成同步加載即可。
借助類解決模塊間的相互干擾//C模塊 define([],function(){ // 定義一個類 function DemoClass() { var count = 0; this.say = function(){ count++; return count; }; } return function(){ //每次都返回一個新對象 return new DemoClass(); }; }); // A模塊 require(["C"], function(module) { cosole.log(module().say());//1 }); // B模塊 require(["C"], function(module) { cosole.log(module().say());//1 });
文檔:官方文檔,
[中文版](https://blog.csdn.net/wangzhanzheng/article/details/79050033)seajs
Sea.js 追求簡單、自然的代碼書寫和組織方式,具有以下核心特性:
簡單友好的模塊定義規范:Sea.js 遵循 CMD 規范,可以像 Node.js 一般書寫模塊代碼。
自然直觀的代碼組織方式:依賴的自動加載、配置的簡潔清晰,可以讓我們更多地享受編碼的樂趣。
通過exports + require實現模塊的加載與導出。
引入config
//seajs配置 seajs.config({ //1.頂級標識始終相對 base 基礎路徑解析。 //2.絕對路徑和根路徑始終相對當前頁面解析。 //3.require 和 require.async 中的相對路徑相對當前模塊路徑來解析。 //4.seajs.use 中的相對路徑始終相對當前頁面來解析。 // Sea.js 的基礎路徑 在解析頂級標識時,會相對 base 路徑來解析 base 的默認值為 sea.js 的訪問路徑的父級 base: "./", // 路徑配置 當目錄比較深,或需要跨目錄調用模塊時,可以使用 paths 來簡化書寫 paths: { gallery: "https://a.alipayobjects.com/gallery" /* var underscore = require("gallery/underscore"); //=> 加載的是 https://a.alipayobjects.com/gallery/underscore.js */ }, // 別名配置 當模塊標識很長時,可以使用 alias 來簡化(相當于 base 設置的目錄為基礎) //Sea.js 在解析模塊標識時, 除非在路徑中有問號(?)或最后一個字符是井號(#),否則都會自動添加 JS 擴展名(.js)。如果不想自動添加擴展名,可以在路徑末尾加上井號(#)。 alias: { "seajs-css": "~/lib/seajs/plugins/seajs-css", "seajs-text": "~/lib/seajs/plugins/seajs-text", "$": "~/lib/zepto/zepto" }, // 變量配置 有些場景下,模塊路徑在運行時才能確定,這時可以使用 vars 變量來配置 vars: { //locale: "zh-cn" /* var lang = require("./i18n/{locale}.js"); //=> 加載的是 path/to/i18n/zh-cn.js */ }, // 映射配置 該配置可對模塊路徑進行映射修改,可用于路徑轉換、在線調試等 map: [ //[".js", "-debug.js"] /* var a = require("./a"); //=> 加載的是 ./js/a-debug.js */ ], // 預加載項 在普通模塊加載前,提前加載并初始化好指定模塊 preload 中的配置,需要等到 use 時才加載 preload: ["seajs-css","seajs-text"], // 調試模式 值為 true 時,加載器不會刪除動態插入的 script 標簽。插件也可以根據 debug 配置,來決策 log 等信息的輸出 debug: true, // 文件編碼 獲取模塊文件時, 一樣,會相對當前頁面解析 use用來在頁面中加載一個或多個模塊。seajs.use 理論上只用于加載啟動,不應該出現在 define 中的模塊代碼里。在模塊代碼里需要異步加載其他模塊時,推薦使用 require.async 方法。
// 加載一個模塊 seajs.use("./a"); // 加載一個模塊,在加載完成時,執行回調 seajs.use("./a", function(a) { a.doSomething(); }); // 加載多個模塊,在加載完成時,執行回調 seajs.use(["./a", "./b"], function(a, b) { a.doSomething(); b.doSomething(); });define// 方式一 define(function(require, exports, module) { // 模塊代碼 var a = require("a") }); // 方式二,此方法嚴格來說不屬于CMD規范 define( "module", ["module1", "module2"], function( require, exports, module ){ // 模塊代碼 }); // 如果模塊內容僅是對象或者字符串 define({ "foo": "bar" }); define("I am a template. My name is {{name}}.");requirerequire 是一個方法,接受 模塊標識作為唯一參數,用來獲取其他模塊提供的接口。
同步執行此方式,require 的參數值 必須 是字符串直接量。
var a = require("./a");異步回調執行require.async 方法用來在模塊內部異步加載模塊,并在加載完成后執行指定回調。callback 參數可選。
此時,參數值可以是動態的,以實現動態加載。define(function(require, exports, module) { // 異步加載一個模塊,在加載完成時,執行回調 require.async("./b", function(b) { b.doSomething(); }); // 異步加載多個模塊,在加載完成時,執行回調 require.async(["./c", "./d"], function(c, d) { c.doSomething(); d.doSomething(); }); });require.resolve 使用模塊系統內部的路徑解析機制來解析并返回模塊絕對路徑。
define(function(require, exports) { console.log(require.resolve("./b")); // ==> http://example.com/path/to/b.js });exportsexports 是一個對象,用來向外提供模塊接口,也可以使用return或者module.exports來進行導出
define(function(require, exports) { // 對外提供 foo 屬性 exports.foo = "bar"; // return return { foo: "bar", doSomething: function() {} }; // module.exports module.exports = { foo: "bar", doSomething: function() {} }; });modulemodule 是一個對象,上面存儲了與當前模塊相關聯的一些屬性和方法。
module.id 模塊的唯一標識
module.uri 根據模塊系統的路徑解析規則得到的模塊絕對路徑
module.dependencies 表示當前模塊的依賴
module.exports 當前模塊對外提供的接口
其他 插件seajs-css
seajs-preload
seajs-text
seajs-style
seajs-combo
seajs-flush
seajs-debug
seajs-log
seajs-health
文檔:官方文檔
ESModule 簡介在 ES6 之前,社區制定了一些模塊加載方案,最主要的有 CommonJS 和 AMD 兩種。前者用于服務器,后者用于瀏覽器。ES6 在語言標準的層面上,實現了模塊功能,而且實現得相當簡單,完全可以取代 CommonJS 和 AMD 規范,成為瀏覽器和服務器通用的模塊解決方案。
嚴格模式ES6 的模塊自動采用嚴格模式,不管你有沒有在模塊頭部加上"use strict";。
嚴格模式主要有以下限制:
變量必須聲明后再使用
函數的參數不能有同名屬性,否則報錯
不能使用with語句
不能對只讀屬性賦值,否則報錯
不能使用前綴 0 表示八進制數,否則報錯
不能刪除不可刪除的屬性,否則報錯
不能刪除變量delete prop,會報錯,只能刪除屬性delete global[prop]
eval不會在它的外層作用域引入變量
eval和arguments不能被重新賦值
arguments不會自動反映函數參數的變化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局對象
不能使用fn.caller和fn.arguments獲取函數調用的堆棧
增加了保留字(比如protected、static和interface)
export 命令定義模塊的對外接口。
一個模塊就是一個獨立的文件。該文件內部的所有變量,外部無法獲取。如果你希望外部能夠讀取模塊內部的某個變量,就必須使用export關鍵字輸出該變量。
以下是幾種用法://------輸出變量------ export var firstName = "Michael"; export var lastName = "Jackson"; //等價于 var firstName = "Michael"; export {firstName}; //推薦,能清除知道輸出了哪些變量 //------輸出函數或類------ export function multiply(x, y) { return x * y; }; //------輸出并as重命名------ var v1 = "Michael"; function v2() { ... } export { v1 as streamV1, v2 as streamV2 }; //------輸出default------ export default function () { ... }注意:export default在一個模塊中只能有一個。
import 命令使用export命令定義了模塊的對外接口以后,其他 JS 文件就可以通過import命令加載這個模塊。
以下是幾種用法,必須和上面的export對應://------加載變量、函數或類------ import {firstName, lastName} from "./profile.js"; //------加載并as重命名------ import { lastName as surname } from "./profile.js"; //------加載有default輸出的模塊------ import v1 from "./profile.js"; //------執行所加載的模塊------ import "lodash"; //------加載模塊所有輸出------ import * as surname from "./profile.js";復合寫法如果在一個模塊之中,先輸入后輸出同一個模塊,import語句可以與export語句寫在一起。
export { foo, bar } from "my_module"; // 等同于 import { foo, bar } from "my_module"; export { foo, bar };不完美只能出現在模塊頂層,不能在其他語句中
無法動態加載,其實這點主要是為了保證靜態分析,所有的模塊都要在解析階段確定它的依賴
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105832.html
摘要:隨著前端的發展,異步這個詞真是越來越常見了。真正帶來革命性改變的是規范。借助,我們可以這樣完成異步任務好棒寫起來像同步處理的函數一樣別著急,少年。總結以上就是筆者總結的幾種異步編程模式。 隨著前端的發展,異步這個詞真是越來越常見了。假設我們現在有這么一個異步任務: 向服務器發起數次請求,每次請求的結果作為下次請求的參數。 來看看我們都有哪些處理方法: Callbacks ...
摘要:大潮來襲前端開發能做些什么去年谷歌和火狐針對提出了的標準,顧名思義,即的體驗方式,我們可以戴著頭顯享受沉浸式的網頁,新的標準讓我們可以使用語言來開發。 VR 大潮來襲 --- 前端開發能做些什么 去年谷歌和火狐針對 WebVR 提出了 WebVR API 的標準,顧名思義,WebVR 即 web + VR 的體驗方式,我們可以戴著頭顯享受沉浸式的網頁,新的 API 標準讓我們可以使用 ...
摘要:不同于其它靜態編程語言,實現組合模式的難點是保持樹對象與葉對象之間接口保持統一,可借助定制接口規范,實現類型約束。誤區規避組合不是繼承,樹葉對象并不是父子對象組合模式的樹型結構是一種聚合的關系,而不是。 showImg(https://segmentfault.com/img/bVbu79V?w=800&h=600); 組合模式:又叫 部分整體 模式,將對象組合成樹形結構,以表示 部分...
摘要:權威指南第六版關于閉包的說明采用詞法作用域,也就是說函數的執行依賴于變量的作用域,這個作用域是在函數定義時決定的,而不是函數調用時決定的。閉包這個術語的來源指函數變量可以被隱藏于作用域鏈之內,因此看起來是函數將變量包裹了起來。 最近打算換工作,所以參加了幾次面試(國內比較知名的幾家互聯網公司)。在面試的過程中每當被問起閉包,我都會說閉包是作用域的問題?令人驚訝的是幾乎無一例外的當我提到...
摘要:原型繼承基本模式這種是最簡單實現原型繼承的方法,直接把父類的對象賦值給子類構造函數的原型,這樣子類的對象就可以訪問到父類以及父類構造函數的中的屬性。 真正意義上來說Javascript并不是一門面向對象的語言,沒有提供傳統的繼承方式,但是它提供了一種原型繼承的方式,利用自身提供的原型屬性來實現繼承。Javascript原型繼承是一個被說爛掉了的話題,但是自己對于這個問題一直沒有徹底理解...
閱讀 1369·2021-10-13 09:39
閱讀 1333·2021-09-23 11:22
閱讀 2243·2019-08-30 14:05
閱讀 1059·2019-08-29 17:03
閱讀 771·2019-08-29 16:24
閱讀 2227·2019-08-29 13:51
閱讀 656·2019-08-29 13:00
閱讀 1290·2019-08-29 11:24