![]()
一個函數有10個參數是什么體驗?MiniScript開發者Joe Strout最近曬了段代碼:調用PixelDisplay.drawImage時,光是記住參數順序就得先查文檔。更離譜的是,哪怕只想改最后一個參數,前面9個占位符也得老老實實填上。
這種"參數地獄"在Mini Micro里真實存在——drawImage方法有10個參數,從位置、尺寸到裁剪區域、顏色疊加,全部擠在括號里。
Joe Strout在MiniScript社區文檔里寫得很直白:「我經常在Mini Micro命令行敲@gfx.saveImage,不為別的,就為了確認參數順序。」
為什么MiniScript故意不做"命名參數"
很多現代語言支持按名稱傳參,比如Python的drawImage(image=img, tint=color.aqua)。這看起來很方便,但Strout認為這是代碼腐爛的溫床。
他舉了個親身經歷:曾維護過一個25參數的怪物函數,「簡直是噩夢」。命名參數會讓開發者放松警惕,覺得「多加一個參數也沒事」,結果函數膨脹到只有特定參數組合才合法,內部塞滿校驗邏輯,文檔比代碼還長。
Strout的毒舌評價:「很少見到哪種語言特性能這么快催生爛代碼,GOTO在這方面可能都要甘拜下風。」
MiniScript的設計哲學是:參數多了,說明抽象層級出了問題。與其在語法層面縱容,不如逼開發者直面重構。
參數對象:把10個變量打包成1個字典
解決方案來自經典重構手法「引入參數對象」(Introduce Parameter Object)。核心操作:把散落的參數收進一個對象,調用方按需填充,接收方自主解析。
以drawImage為例,原函數簽名長這樣:
FUNCTION(self, image, left=0, bottom=0, width=-1, height=-1, srcLeft=0, srcBottom=0, srcWidth=-1, srcHeight=-1, tint="#FFFFFF")
Strout寫了個包裝函數,只收一個params參數:
drawImage = function(params) g = params.get("gfx", gfx) g.drawImage params.image, params.get("left", 0), params.get("bottom", 0), params.get("width", -1), params.get("height", -1), params.get("srcLeft", 0), params.get("srcBottom", 0), params.get("srcWidth", -1), params.get("srcHeight", -1), params.get("tint", "#FFFFFF") end function
調用方式徹底變樣。原來要記位置:
gfx.drawImage img, 500, 200, -1, -1, 0, 0, -1, -1, color.aqua
![]()
現在寫成自描述的結構:
drawImage { "image": img, "left": 500, "bottom": 200, "tint": color.aqua }
沒指定的字段自動走默認值,新增參數也不會破壞舊代碼——這是字典結構比位置參數更抗造的地方。
從"填表"到"造句":代碼可讀性的質變
參數對象的價值不只是省掉占位符。Strout在文檔里強調,當同一組參數在多個函數間傳遞時(比如UI框架的繪制流水線),字典比位置參數更能表達「這些字段屬于同一語境」。
MiniScript的mapUtil模塊提供了params.get(key, default)語法,讓默認值處理比原生函數參數更靈活——你可以根據運行時條件動態決定缺省值,而不是寫死在函數簽名里。
這種模式和JavaScript的options對象、Python的**kwargs異曲同工,但MiniScript的實現更極簡:沒有專門的語法糖,純靠字典操作完成。Strout認為這反而是優勢——「顯式比隱式好」,調用方清楚看到自己在組裝一個配置包,而不是被編譯器偷偷轉換。
一個細節:Strout的示例代碼里,params.image沒有用.get(),而是直接點訪問。這是他刻意為之——image是必傳字段,缺了就該報錯,而不是靜默走默認值。
這種「必填vs可選」的區分,用傳統參數列表很難表達,在字典結構里卻一目了然。
小型語言的固執:為什么MiniScript拒絕"便利"
MiniScript的定位是嵌入式腳本語言,主打「小到能裝進任何游戲引擎」。Strout在設計文檔里多次提到,每增加一個語法特性,都要付出實現復雜度和學習成本的代價。
命名參數屬于「看起來簡單,做起來重」的特性:解析器要支持新語法,IDE要補全參數名,文檔工具要生成新格式。更隱蔽的成本是心理暗示——開發者會傾向于濫用,直到函數參數數突破認知負荷上限。
參數對象沒有這些包袱。它不依賴語言特性,純是代碼組織技巧;從Python到Lua到JavaScript,任何支持字典/對象的語言都能用。Strout把這稱為「可移植的最佳實踐」。
他在文檔結尾留了個開放場景:如果你發現自己在多個函數里重復傳遞同一組參數(比如渲染上下文、坐標變換矩陣),就該考慮把它們封裝成「上下文對象」。這比每個函數加參數更干凈,也比全局變量更可控。
Mini Micro的drawImage有10個參數,是歷史遺留而非設計目標。Strout的示例代碼暗示:如果今天重寫,API可能會直接設計成接收單個options字典——就像現代Canvas 2D API的drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)雖然參數多,但Web開發者更常用的是封裝后的庫,把參數收進配置對象。
這種「底層保留靈活性,上層封裝易用性」的分層思路,在MiniScript社區文檔里反復出現。參數對象不是萬能藥,但在「不想改動原生API」的約束下,它提供了足夠優雅的逃生通道。
Joe Strout在文檔最后沒給結論,只放了一段可運行的代碼示例。有讀者在評論區問:「如果參數對象嵌套太深怎么辦?」Strout回復:「那就說明你需要不止一個對象。」
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.