读取函数的可选参数的名称

时间:2010-07-14 02:42:57

标签: javascript

我有一堆函数(实际上是类的方法),我正在编写一个方法来记录与数组中其他方法的交互。 例如:

 foo = Base.extend ({
      a : function (a1,a2){
            ....
      },
      b:function(b1,b2){
        ...
      },
      history : function(){ ... }
  })

为了简化历史记录方法,我想读取可选参数的名称并将它们添加到数组中,例如,如果调用方法a,我想记录a1,a2 ...... 所以基本上,有没有办法在javascript中读取数组的可选参数列表的名称?

这是代码:

var element = Base.extend({
constructor : function() {
    if(arguments.length==1){
        ...
    }else{
        ...
    }
},
setLocation : function (top, left){
    oldArgs = [this.top,this.left];
    this.top = top;
    this.left = left;
    return(oldArgs);
},
setAspects : function (width, height){
    oldArgs = [this.width,this.height]
    this.width = width;
    this.height = height;
    return(oldArgs);
},
draw : function (page){
    ...
},
delet : function () {
        ...
},
$ : function(method,args){
    var oldArgs = this[method].apply(this,args);
    this.history(method,oldArgs);
    Nx.pages[this.page].modified = true;
},
history : function (method,args){
    Nx.history[Nx.history.length]=[this.id,method,args]
}

})

所以在这个类中,如果我想调用任何方法,我将通过$方法传递它,它将调用history方法,到目前为止我所做的是例如在setLocation方法中它将返回旧的参数,我将在我的数组Nx.history中对它们进行编辑,但是更方便的是在方法中对所有这些“返回”调用进行分解,并在$方法中添加一行,该行读取预期参数的名称。方法,并将其发送到历史方法,所以像这样:

$ : function(method,args){
    this[method].apply(this,args);
    **var oldArgs = this[method].arguments // get the list of argument names here
    $.each(oldArgs, function(value) { Args[Args.length] = this.value //get the stored value in the class
    })
    this.history(method,Args); // and pass it to the history**
    Nx.pages[this.page].modified = true;
}

4 个答案:

答案 0 :(得分:2)

2.0

这个较新版本的想法是预先定义要为对象记录的属性。这是一个重复级别,但它只是一次性的事情。然后,在构造函数中,为每个属性创建属性设置器。设置者在设置属性的同时做了一些工作。它将参数名称和值压入堆栈,并分配属性。 $方法应该调用调用适当的方法。调用完成后,将使用该函数中设置的参数填充堆栈。弹出该堆栈中的每个参数,直到堆栈为空。然后使用方法名称调用历史记录,以及刚刚从堆栈中弹出的参数。如果这没有任何意义,请告诉我,我可能要更好地说出来。

See an example here

这是一个用MooTools编写的代码示例,它与您的Base类略有相似。

var Device = new Class({
    _properties: ['top', 'left', 'width', 'height'],

    _parameterStack: [],

    initialize: function() {
        this._createPropertyAccessors();
    },

    _createPropertyAccessors: function() {
        this._properties.each(function(property) {
            Object.defineProperty(this, property, {
                enumerable: true,
                configurable: true,
                set: function(value) {
                    var o = {};
                    o[property] = value;
                    // push the parameter onto the stack
                    this._parameterStack.push(o);
                }.bind(this)
            });
        }.bind(this));
    },

    // method stays unchanged
    setLocation: function(top, left) {
        this.top = top;
        this.left = left;
    },

    setAspects: function(width, height) {
        this.width = width;
        this.height = height;
    },

    // dispatches call to method
    // pops off the entire stack
    // passed method name, and emptied stack arguments to history
    $: function(method, args) {
        this[method].apply(this, args);
        var argsStack = [];
        while(this._parameterStack.length) {
            argsStack.push(this._parameterStack.pop());
        }
        this.history(method, argsStack);
    },

    history: function(method, args) {
        console.log("%s(%o) called", method, args);
    }
});

1.0

传递给JavaScript函数的参数可以通过名为arguments类似数组的对象访问,该对象可用于所有函数。

调用history时,将arguments对象传递给它。

a: function(a1, a2) {
    this.history.apply(this, arguments);
}
然后将调用

history,就好像它是使用两个参数调用this作为基础对象 - foo,除非您使用不同的上下文调用它。

我不确定Base如何发挥作用。你必须在这里详细说明Base的作用。

这是一个简单的例子:

var foo = {
    a: function(a1, a2) {
        this.history.apply(this, arguments);
    },
    history: function() {
        console.log("history received " + arguments.length + " arguments.");
    }
};

foo.a("hello", "world"); // history received 2 arguments

另请注意,尽管此处a有两个命名参数,但我们仍然可以传递任意数量的参数,并且所有这些参数将依次传递给history方法。我们可以将a称为:

foo.a(1, 2, 3); // history received 3 arguments

答案 1 :(得分:2)

我不是100%肯定你要求的 - 一种提取函数形式参数名的方法吗?

我不知道这是否可行,但是你能解析函数的字符串表示来提取参数名吗?

这可能是一个非常蹩脚的解决方案,但您可以做类似的事情:

function getArgNames(fn) {
    var args = fn.toString().match(/function\b[^(]*\(([^)]*)\)/)[1];
    return args.split(/\s*,\s*/);
}

答案 2 :(得分:1)

这样的事情应该有效。如果要访问已使用的参数,可以遍历包含参数列表的foo.history数组。

var foo = {
    storeArgs: function (fn) { 
                 return function() { 
                    this.history += arguments
                    return fn.apply(null, arguments); 
                 }
              },

    a: storeArgs(function(a1, a2) {
        alert(a1+a2);
    }),

    history: []
};

我看了你的最新帖子。你是什​​么意思“名字?”变量名称?例如,如果某人调用了a(1337),您是否希望将["a1"]添加到数组中?如果a(1337, 132)被调用,["a1", "a2"]会被添加吗?我认为没有任何理智的方法可以做到这一点。

这是我能做的最好的事情。使用storeArgs函数定义函数时,必须包含参数名列表。

var foo = {
    storeArgs: function (params, fn) { 
                 return function() { 
                    var arr = [];
                    for (var i = 0; i < arguments.length; i++) {
                       arr.push(params[i]);
                    }
                    this.history += arr;
                    return fn.apply(null, arguments); 
                 }
              }

    a: storeArgs(["a1", "a2"], function(a1, a2) {
        alert(a1+a2);
    }),

    history: []
};

让我知道它是否有效。

答案 3 :(得分:0)

这适用于IE,但我不确定其他浏览器......

Function.prototype.params = function() {
    var params = this.toString().split(/(\r\n)|(\n)/g)[0];
    params = params.trim().replace(/^function.*?\(/, "");
    params = params.match(/(.*?)\)/)[1].trim();

    if (!params) {
        return([]);
    }

    return(params.split(/, /g));
};

function Test(a, b) {
  alert(Test.params());
}

Test();