摘要:本文同步自我的博客前言這個模塊實際上才是模塊系統中對外的模塊,它包含了之前介紹的類和類,以及自己內部的模塊和模塊,因此模塊是真正的基礎類。這兩個方法的作用就是針對類上的某個方法,給這個方法綁定先于其執行和后于其執行的回調函數。
本文同步自我的GitHub博客
前言Base這個模塊實際上才是Arale模塊系統中對外的模塊,它包含了之前介紹的Class類和Events類,以及自己內部的attribute模塊和aspect模塊,因此Base模塊是真正的基礎類。
由于Attribute模塊的內容太多,而Aspect模塊和它關系也不太大,因此,考慮到文章篇幅的平衡,將Base模塊的解析分成兩篇,Attribute模塊的分析放在下一篇多帶帶來寫。
帶注釋源碼Base源碼的開頭是這樣的:
var Class = require("arale-class"); var Events = require("arale-events"); var Aspect = require("./aspect"); var Attribute = require("./attribute");
可見,整個Base的實現是基于上面這四個模塊的,前兩個模塊已經分析過了,下面來分析后面兩個模塊。首先是Aspect模塊,這個模塊實際上只提供了兩個方法before和after:
// `before`和`after`實際上是對`weave`方法的一次封裝,提供易用的接口 // 在指定方法執行前,先執行 callback exports.before = function(methodName, callback, context) { return weave.call(this, "before", methodName, callback, context); }; // 在指定方法執行后,再執行 callback exports.after = function(methodName, callback, context) { return weave.call(this, "after", methodName, callback, context); }; // Helpers // ------- // 事件分割 var eventSplitter = /s+/; /** * 控制callback的執行時序 * @param {String} when 選擇是`before`還是`after` * @param {String} methodName 方法名字符串 * @param {Function} callback 回調函數 * @param {Object} context 上下文對象 * @return {Object} 調用此方法的對象 */ function weave(when, methodName, callback, context) { // 取得方法名數組 var names = methodName.split(eventSplitter); var name, method; // 遍歷方法名數組 while (name = names.shift()) { // 取得方法函數 method = getMethod(this, name); // 方法是否被改造過,如果沒有則進行改造 if (!method.__isAspected) { wrap.call(this, name); } // 綁定一下事件 this.on(when + ":" + name, callback, context); } return this; } /** * 取得對應名稱的方法 * @param {Object} host 調用對象 * @param {String} methodName 方法名稱 * @return {Function} 方法函數 */ function getMethod(host, methodName) { // 取得對象上對應的方法函數 var method = host[methodName]; // 如果方法不存在則報錯 if (!method) { throw new Error("Invalid method name: " + methodName); } return method; } /** * [wrap description] * @param {[type]} methodName [description] * @return {[type]} [description] */ function wrap(methodName) { // 取得對象上的方法 var old = this[methodName]; // 對方法進行改造封裝 // 改造過的方法執行時,會先觸發"before:methodName"事件 this[methodName] = function() { // 切分參數 var args = Array.prototype.slice.call(arguments); // 在參數數組前添加一項"before:methodName" var beforeArgs = ["before:" + methodName].concat(args); // prevent if trigger return false // 先觸發`before:methodName`事件,如果存在回調函數隊列且執行后返回false,則阻止進一步往下執行 if (this.trigger.apply(this, beforeArgs) === false) return; // 執行原方法,保存返回值 var ret = old.apply(this, arguments); // 構造參數數組,執行`after:methodName`事件 var afterArgs = ["after:" + methodName, ret].concat(args); this.trigger.apply(this, afterArgs); return ret; }; // 修改方法是否被改造狀態屬性 this[methodName].__isAspected = true; }
然后是Base模塊,它集成了Event, Aspect和Attribute模塊的各種屬性,實際上是Arale類庫的一個入口模塊:
var Class = require("arale-class"); var Events = require("arale-events"); var Aspect = require("./aspect"); var Attribute = require("./attribute"); module.exports = Class.create({ // 混入Events, Aspect, Attribute模塊的所有屬性 Implements: [Events, Aspect, Attribute], // 所有用`Base.extend()`構建的類在初始化時都會調用的方法 initialize: function(config) { this.initAttrs(config); // 將`this._onChangeAttr`注冊為`change:attr`事件的監聽函數 parseEventsFromInstance(this, this.attrs); }, destroy: function() { // 卸載所有事件監聽 this.off(); // 清除所有屬性 for (var p in this) { if (this.hasOwnProperty(p)) { delete this[p]; } } // destroy一次后this都被清除了,再次調用會報錯,因此生成一個空的destroy,該方法與主同在 this.destroy = function() {}; } }); /** * 將`_onChangeAttr`方法注冊為`change:attr`事件的監聽函數 * @param {Class} host 調用對象 * @param {Object} attrs 包含所有要注冊屬性的對象 */ function parseEventsFromInstance(host, attrs) { for (var attr in attrs) { if (attrs.hasOwnProperty(attr)) { // 檢測attr是attrs的非繼承屬性 var m = "_onChange" + ucfirst(attr); if (host[m]) { host.on("change:" + attr, host[m]); } } } } /** * 將首字母轉變為大寫 * @param {String} str 要處理的字符串 * @return {String} 處理完的字符串 */ function ucfirst(str) { return str.charAt(0).toUpperCase() + str.substring(1); }源碼分析 Aspect
Aspect模塊就是實現了兩個方法,before和after。這兩個方法的作用就是針對類上的某個方法,給這個方法綁定先于其執行和后于其執行的回調函數。
兩個方法實際上調用的都是同一個方法weave,只是將before和after作為參數傳入,在weaver方法中,對要進行before和after“偽事件”綁定的方法進行查找,找到后會檢測這個方法上是否有__isAspected屬性。這個屬性的作用是標示出此方法有沒有被進行過偽事件的“包裝”。
上一段連續提到兩次“偽事件”這個詞,它是我編出來的,表示的意思為before:methodName和after:methodName這樣的事件并不能成為一個獨立的事件,而是依附于methodName這個原方法的。原來的事件執行流程是這樣的。
event.trigger(eventName) +------------+ ------------------------->| someMethod |----------->被觸發執行 +------------+
一旦在someMethod上注冊了after或before事件后,someMethod就會被封裝成一個新的函數:
someMethod被封裝后生成的新wrappedMethod: |trigger() +-------------------------------------------------------+ |wrappedMethod: |觸發`before:method`事件 | | | | | +---------------+ return false +-----+ | | | beforeMethod |-------------->| end | | | +---------------+ +-----+ | | |return true | | | | | +---------------+ | | | method | | | +---------------+ | | |觸發`after:method`事件 | | | | | +---------------+ | | | afterMethod | | | +---------------+ | +-------------------------------------------------------+
整個模塊的關鍵就在于wrap這個用來封裝方法的函數了,當然實現這一功能的也需要功能完備的Event模塊的支持。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85373.html
摘要:先來看源碼中,首先是做的是參數的處理工作,針對某些參數未傳的情況作了調整,最后達到的效果是的值為傳入的父類構造函數,如果沒有,設為。下一個語句其作用是處理父類構造函數沒有修改的屬性值并且有方法的時候,在上調用方法。 本文同步自我的GitHub 概述 Arale是支付寶開發的一套基礎類庫,提供了一整套前端模塊架構,基于CMD規范,所有模塊均是以sea.js的標準進行開發。其開發過程借...
摘要:在方法執行后,再執行函數函數在執行時,接收的參數第一個是的返回值,之后的參數和傳給相同。的返回值源碼定義兩個出口定義一個可柯里化的函數,柯里化成函數指向基于生成的類的實例,如上例的如果該函數是第一次切面化綁定,則包裝該函數。 系列文章:讀 arale 源碼之 class 篇 使用 Aspect,可以允許你在指定方法執行的前后插入特定函數 before object.before(me...
摘要:帶注釋源碼用于分割事件名的正則,識別空格介紹使用方法,這個模塊可以混入任何對象之中,實現對自定義事件的資瓷將空格分割的事件綁定給對象,事件名為的話,事件回調函數在任何事件被觸發時都會調用。 帶注釋源碼 // Regular expression used to split event strings // 用于分割事件名的正則,識別空格 var eventSplitter = /s+...
摘要:系列文章讀源碼之篇提供基本的屬性添加獲取移除等功能。判斷是否為等對象特性檢查閉包實現塊作用域,不污染全局變量。找這個屬性,若沒有則返回空對象執行函數,返回被修改的值。 系列文章:讀 arale 源碼之 class 篇 attributes 提供基本的屬性添加、獲取、移除等功能。它是與實例相關的狀態信息,可讀可寫,發生變化時,會自動觸發相關事件 先來了解一下 Attribute 模塊要實...
摘要:的變化利用進行前后端通知。例如的副作用,資源只有資源等等,仔細剖析還有很多有趣的點擴展閱讀創建熱更新流程本文示例代碼聯系我 前置知識 首先可能你需要知道打包工具是什么存在 基本的模塊化演變進程 對模塊化bundle有一定了解 了解babel的一些常識 對node有一定常識 常見的一些打包工具 如今最常見的模塊化構建工具 應該是webpack,rollup,fis,parcel等等各...
閱讀 2771·2021-10-11 11:08
閱讀 1489·2021-09-30 09:48
閱讀 1049·2021-09-22 15:29
閱讀 1037·2019-08-30 15:54
閱讀 976·2019-08-29 15:19
閱讀 527·2019-08-29 13:12
閱讀 3161·2019-08-26 13:53
閱讀 957·2019-08-26 13:28