FunctionBase 函數基類
檔案:FunctionBase.js
var $FunctionMapper = [];</p><p>// Global function mapper<br />function $RegisterFunction(funcObj) {<br /> if ($FunctionMapper[funcObj.get_FunctionName().toLowerCase()] != null)<br /> throw new Exception(this, "$RegisterFunction:" + funcObj.get_FunctionName() + " has registered");</p><p> $FunctionMapper[funcObj.get_FunctionName().toLowerCase()] = funcObj;<br />};</p><p>function $GetRegisterFunction(funcname)<br />{<br /> if ($FunctionMapper[funcname.toLowerCase()] != null)<br /> return $FunctionMapper[funcname.toLowerCase()];<br /> else<br /> return null;<br />}</p><p>// --------------- FunctionBase --------------<br />function FunctionBase() {<br /> this.DeriveFrom(new OperatorBase());<br /> this.set_ClassName("FunctionBase");<br /> this._type = new FunctionType("undefined");<br />};</p><p>FunctionBase.prototype = {<br /> get_FunctionName: function() { return this.get_Sign(); },<br /> Evaluate: function(args) {<br /> throw new Exception(this, "Not implemented");<br /> } // Evaluate<br />}; // FunctionBase.prototype<br />
注意,這裡的的實現是:公式解析時可以沒有函數定義,而在公式解釋時對通過全域$FunctionMapper表進行函數名尋找。相應的,
函數在需要通過$RegisterFunction進行註冊。
因為可以不知道函數的先驗知識,所以需要一個定義來表示函數,該定義就是FunctionUnknown類。
FunctionUnknown類
檔案:FunctionBase.js
// ------------- FunctionUnknown ------------------<br />// Used for function parser<br />function FunctionUnknown(arg) {<br /> this.DeriveFrom(new FunctionBase());<br /> this.set_ClassName("FunctionUnknown");</p><p> if (arg != null)<br /> this.set_Sign(arg.ToString());<br /> else<br /> this.set_Sign("undefined");<br />};</p><p>FunctionUnknown.prototype.Evaluate = function(args) {<br /> var values = [];</p><p> for(var i = 0; i < args.length; i++)<br /> values.push(args[i].get_Value());</p><p> $Debug.WriteLine("Undefined function:" + this.get_Sign() + "(" + values.join(",") + "), assume return 0.");<br /> return new OperandNumber(0);<br />};</p><p>// Register operation should be performed after the prototype defined.<br />$RegisterFunction(new FunctionUnknown());
各類函數的實現
這裡沒有實現全部Excel函數,僅有“常用”目錄下的幾個,其中PMT的公式未知,所以也沒有實現,留待家庭作業吧:-P。
/// Function Template<br />/*<br />function FunctionXXX() {<br /> this.DeriveFrom(new FunctionBase());<br /> this.set_ClassName("FunctionXXX");<br /> this.set_Sign("XXX");<br />};</p><p>FunctionXXX.prototype.Evaluate = function(args) {</p><p> // should return a value<br />};</p><p>$RegisterFunction(new FunctionXXX());<br />*/</p><p>///////////////////////////////////////////<br />// SUM<br />///////////////////////////////////////////<br />function FunctionAverage() {<br /> this.DeriveFrom(new FunctionBase());<br /> this.set_ClassName("FunctionAverage");<br /> this.set_Sign("Average");<br />};</p><p>FunctionAverage.prototype = {<br /> Evaluate: function(args) {<br /> var res = 0;</p><p> for (var i = 0; i < args.length; i++) {<br /> if (!(args[i].IsNumber() || args[i].IsBoolean()))<br /> throw new Exception(this, "Evaluate", "Unsupported argument:" + $T(args[i]));</p><p> res += args[i].get_Value();<br /> }</p><p> return new OperandNumber(res / args.length);<br /> }<br />};</p><p>$RegisterFunction(new FunctionAverage());</p><p>///////////////////////////////////////////<br />// Average<br />///////////////////////////////////////////<br />function FunctionSum() {<br /> this.DeriveFrom(new FunctionBase());<br /> this.set_ClassName("FunctionSum");<br /> this.set_Sign("Sum");<br />};</p><p>FunctionSum.prototype.Evaluate = function(args) {<br /> var res = 0;</p><p> for (var i = 0; i < args.length; i++) {<br /> if (!(args[i].IsNumber() || args[i].IsBoolean()))<br /> throw new Exception(this, "Evaluate", "Unsupported argument:" + $T(args));</p><p> res += args[i].get_Value();<br /> }</p><p> return new OperandNumber(res);<br />};</p><p>$RegisterFunction(new FunctionSum());</p><p>///////////////////////////////////////////<br />// IF<br />///////////////////////////////////////////<br />function FunctionIF() {<br /> this.DeriveFrom(new FunctionBase());<br /> this.set_ClassName("FunctionIF");<br /> this._type = new FunctionType("IF", 3);<br />};</p><p>FunctionIF.prototype.Evaluate = function(args) {<br /> if (!args[0].IsBoolean())<br /> throw new Exception(this, "Evaluate", "First argument should be boolean");</p><p> return args[0].get_Value() ? args[1] : args[2];<br />};</p><p>$RegisterFunction(new FunctionIF());</p><p>///////////////////////////////////////////<br />// Count<br />///////////////////////////////////////////</p><p>///////////////////////////////////////////<br />// Max<br />///////////////////////////////////////////<br />function FunctionMax() {<br /> this.DeriveFrom(new FunctionBase());<br /> this.set_ClassName("FunctionMax");<br /> this.set_Sign("Max");<br />};</p><p>FunctionMax.prototype.Evaluate = function(args) {<br /> var res = 0;</p><p> for(var i = 1; i < args.length; i++)<br /> if (args[i].IsNumber())<br /> if (res < args[i].get_Value())<br /> res = args[i].get_Value();</p><p> return new OperandNumber(res);<br />};</p><p>$RegisterFunction(new FunctionMax());</p><p>///////////////////////////////////////////<br />// Min<br />///////////////////////////////////////////</p><p>///////////////////////////////////////////<br />// Sin<br />///////////////////////////////////////////<br />function FunctionSin() {<br /> this.DeriveFrom(new FunctionBase());<br /> this.set_ClassName("FunctionSin");<br /> this._type = new FunctionType("Sin", 1);<br />};</p><p>FunctionSin.prototype.Evaluate = function(args) {<br /> return new OperandNumber(Math.sin(args[0].get_Value()));<br />};</p><p>$RegisterFunction(new FunctionSin());</p><p>///////////////////////////////////////////<br />// SUMIF<br />///////////////////////////////////////////<br />function FunctionSumIF() {<br /> this.DeriveFrom(new FunctionBase());<br /> this.set_ClassName("FunctionSumIF");<br /> this.set_Sign("SumIF");<br />};</p><p>FunctionSumIF.prototype.Evaluate = function(args) {</p><p> // Depend on Cell<br /> throw new Exception(this, "Evaluate", "Not implemented");<br />};</p><p>$RegisterFunction(new FunctionSumIF());</p><p>///////////////////////////////////////////<br />// PMT<br />///////////////////////////////////////////<br />function FunctionPMT() {<br /> this.DeriveFrom(new FunctionBase());<br /> this.set_ClassName("FunctionPMT");<br /> this.set_Sign("PMT");<br />};</p><p>FunctionPMT.prototype.Evaluate = function(args) {</p><p> throw new Exception(this, "Evaluate", "Not implemented");<br />};</p><p>$RegisterFunction(new FunctionPMT());<br />///////////////////////////////////////////<br />// STDEV<br />///////////////////////////////////////////<br />function FunctionSTDEV() {<br /> this.DeriveFrom(new FunctionBase());<br /> this.set_ClassName("FunctionSTDEV");<br /> this.set_Sign("STDEV");<br />};</p><p>FunctionSTDEV.prototype.Evaluate = function(args) {<br /> var squareSum = 0,<br /> sum = 0;</p><p> for(var i = 0; i < args; i++) {<br /> squareSum += args[i].get_Value() * args[i].get_Value();<br /> sum += args[i].get_Value();<br /> }</p><p> var res = Math.sqrt((args.length * squareSum - sum * sum) / (args.length * (args.length - 1)));</p><p> return new OperandNumber(res);<br />};</p><p>$RegisterFunction(new FunctionSTDEV());