您的位置:首页 > Web前端 > JavaScript

基于JavaScript的公式解释器 - 11 【函数的实现】

2010-10-19 07:04 716 查看
FunctionBase 函数基类

文件:FunctionBase.js

var $FunctionMapper = [];

// Global function mapper
function $RegisterFunction(funcObj) {
    if ($FunctionMapper[funcObj.get_FunctionName().toLowerCase()] != null)
        throw new Exception(this, "$RegisterFunction:" + funcObj.get_FunctionName() + " has registered");
        
    $FunctionMapper[funcObj.get_FunctionName().toLowerCase()] = funcObj;
};

function $GetRegisterFunction(funcname)
{
    if ($FunctionMapper[funcname.toLowerCase()] != null)
        return $FunctionMapper[funcname.toLowerCase()];
    else
        return null;
}

// --------------- FunctionBase --------------
function FunctionBase() {
    this.DeriveFrom(new OperatorBase());
    this.set_ClassName("FunctionBase");
    this._type = new FunctionType("undefined");
};

FunctionBase.prototype = {
    get_FunctionName: function() { return this.get_Sign(); },
    Evaluate: function(args) {
        throw new Exception(this, "Not implemented");
    } // Evaluate
}; // FunctionBase.prototype




注意,这里的的实现是:公式解析时可以没有函数定义,而在公式解释时对通过全局$FunctionMapper表进行函数名查找。相应的,

函数在需要通过$RegisterFunction进行注册。

因为可以不知道函数的先验知识,所以需要一个定义来表示函数,该定义就是FunctionUnknown类。



FunctionUnknown类

文件:FunctionBase.js

// ------------- FunctionUnknown ------------------
// Used for function parser
function FunctionUnknown(arg) {
    this.DeriveFrom(new FunctionBase());
    this.set_ClassName("FunctionUnknown");
    
    if (arg != null)
        this.set_Sign(arg.ToString());
    else
        this.set_Sign("undefined");
};

FunctionUnknown.prototype.Evaluate = function(args) {
    var values = [];
    
    for(var i = 0; i < args.length; i++)
        values.push(args[i].get_Value());
    
    $Debug.WriteLine("Undefined function:" + this.get_Sign() + "(" + values.join(",") + "), assume return 0.");
    return new OperandNumber(0);
};

// Register operation should be performed after the prototype defined.
$RegisterFunction(new FunctionUnknown());




各类函数的实现

这里没有实现全部Excel函数,仅有“常用”目录下的几个,其中PMT的公式未知,所以也没有实现,留待家庭作业吧:-P。

/// Function Template
/*
function FunctionXXX() {
    this.DeriveFrom(new FunctionBase());
    this.set_ClassName("FunctionXXX");
    this.set_Sign("XXX");
};

FunctionXXX.prototype.Evaluate = function(args) {
    
    // should return a value          
};

$RegisterFunction(new FunctionXXX());
*/

///////////////////////////////////////////
//                  SUM
///////////////////////////////////////////
function FunctionAverage() {
    this.DeriveFrom(new FunctionBase());
    this.set_ClassName("FunctionAverage");
    this.set_Sign("Average");
};

FunctionAverage.prototype = {
    Evaluate: function(args) {
        var res = 0;

        for (var i = 0; i < args.length; i++) {
            if (!(args[i].IsNumber() || args[i].IsBoolean()))
                throw new Exception(this, "Evaluate",  "Unsupported argument:" + $T(args[i]));

            res += args[i].get_Value();
        }

        return new OperandNumber(res / args.length);
    }
};

$RegisterFunction(new FunctionAverage());

///////////////////////////////////////////
//                  Average
///////////////////////////////////////////
function FunctionSum() {
    this.DeriveFrom(new FunctionBase());
    this.set_ClassName("FunctionSum");
    this.set_Sign("Sum");
};

FunctionSum.prototype.Evaluate = function(args) {
    var res = 0;

    for (var i = 0; i < args.length; i++) {
        if (!(args[i].IsNumber() || args[i].IsBoolean()))
            throw new Exception(this,  "Evaluate", "Unsupported argument:" + $T(args));

        res += args[i].get_Value();
    }

    return new OperandNumber(res);
};

$RegisterFunction(new FunctionSum());

///////////////////////////////////////////
//              IF
///////////////////////////////////////////
function FunctionIF() {
    this.DeriveFrom(new FunctionBase());
    this.set_ClassName("FunctionIF");
    this._type = new FunctionType("IF", 3);
};

FunctionIF.prototype.Evaluate = function(args) {
    if (!args[0].IsBoolean())
        throw new Exception(this, "Evaluate", "First argument should be boolean");
            
    return args[0].get_Value() ? args[1] : args[2];
};

$RegisterFunction(new FunctionIF());

///////////////////////////////////////////
//              Count
///////////////////////////////////////////

///////////////////////////////////////////
//              Max
///////////////////////////////////////////
function FunctionMax() {
    this.DeriveFrom(new FunctionBase());
    this.set_ClassName("FunctionMax");
    this.set_Sign("Max");
};

FunctionMax.prototype.Evaluate = function(args) {
    var res = 0;
    
    for(var i = 1; i < args.length; i++)
        if (args[i].IsNumber())
            if (res < args[i].get_Value())
                res = args[i].get_Value();
                
    return new OperandNumber(res);
};

$RegisterFunction(new FunctionMax());

///////////////////////////////////////////
//              Min
///////////////////////////////////////////

///////////////////////////////////////////
//              Sin
///////////////////////////////////////////
function FunctionSin() {
    this.DeriveFrom(new FunctionBase());
    this.set_ClassName("FunctionSin");
    this._type = new FunctionType("Sin", 1);
};

FunctionSin.prototype.Evaluate = function(args) {
    return new OperandNumber(Math.sin(args[0].get_Value()));
};

$RegisterFunction(new FunctionSin());

///////////////////////////////////////////
//              SUMIF
///////////////////////////////////////////
function FunctionSumIF() {
    this.DeriveFrom(new FunctionBase());
    this.set_ClassName("FunctionSumIF");
    this.set_Sign("SumIF");
};

FunctionSumIF.prototype.Evaluate = function(args) {
    
    // Depend on Cell
    throw new Exception(this, "Evaluate", "Not implemented");      
};

$RegisterFunction(new FunctionSumIF());

///////////////////////////////////////////
//              PMT
///////////////////////////////////////////
function FunctionPMT() {
    this.DeriveFrom(new FunctionBase());
    this.set_ClassName("FunctionPMT");
    this.set_Sign("PMT");
};

FunctionPMT.prototype.Evaluate = function(args) {
    
    throw new Exception(this, "Evaluate", "Not implemented");      
};

$RegisterFunction(new FunctionPMT());
///////////////////////////////////////////
//              STDEV
///////////////////////////////////////////
function FunctionSTDEV() {
    this.DeriveFrom(new FunctionBase());
    this.set_ClassName("FunctionSTDEV");
    this.set_Sign("STDEV");
};

FunctionSTDEV.prototype.Evaluate = function(args) {
    var squareSum = 0,
        sum = 0;
        
    for(var i = 0; i < args; i++) {
        squareSum += args[i].get_Value() * args[i].get_Value();
        sum += args[i].get_Value();
    }
    
    var res = Math.sqrt((args.length * squareSum - sum * sum) / (args.length * (args.length - 1)));
    
    return new OperandNumber(res);
};

$RegisterFunction(new FunctionSTDEV());
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: