1 回答

TA貢獻1811條經驗 獲得超5個贊
首先來說,你是希望構造一個函數對象,而它同時又具有你自定義的類方法……這在 ES6 里其實是很容易通過繼承實現的
class Foo extends Function { ... }
不過在 ES5 里也有不是很完美的實現方法,比如改變 f
的 __proto__
為 Foo.prototype
。不過這樣改過之后你會發現 f
不再具有函數對象的一些方法,比如 call()
、apply()
、bind()
等。同時 __proto__
不在標準中,所以不能保證每一個 JS 引擎都實現了。
回過頭來說 ES6 的辦法——因為 ES6 可以通過很多工具,比如 babel
翻譯成 ES5
的,所以 ES6 實現了,ES5 也就能實現 (現在我對這句話表示懷疑——具體請看后面) 。
ES6 中,Foo
從 Function
繼承,所以可以通過 Foo
構造一個函數對象,同時它可以用 Foo
中定義的方法。但問題在于構造這個對象的時候不能使用 function 定義語法,也不能使用函數表達式等,必須直接使用 Function
構造函數。構造函數需要函數體文本為作參數,比如
const f = new Function("console.log(\"Foo\");");
當然函數體很短的時候不是問題,比較長的時候才是麻煩的事情。當然可以用 es6 引入的 模板字符串 來解決,它允許多行字符。這會損失編輯器對其語法的檢查。所以我的辦法是定義一個臨時函數,再通過 toString()
和正則表達式把函數體找出來。
最終完成的代碼是這樣的:
// es6 syntaxconst body = function() { console.log("Foo"); }.toString().replace(/^function\s*\(\)\s*\{|\}$/g, "");class Foo extends Function { constructor() { super(body); } outStr() { console.log("abc"); } }var f = new Foo(); f(); f.outStr();
不過很遺憾,使用 TypeScript 和 Babel 轉出來的 es5 代碼都不能運行……
添加回答
舉報