开发者

read the name of the optional arguments of a function

I have a bunch of functions (methods of a class actually) and I'm writing a method that will record the interactions with other methods in an array. so for example :

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

to simplify the history method, I'd like to read the name of the optional arguments and add them to the array, so for example if the method a is called, I want to record a1,a2 ... so basically, is there any way to read the name of the optional arguments list of an array in javascript ?

here is the code :

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.h开发者_StackOverflow社区eight = 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]
}

})

so in this class, if I want to call any method, I'll pas it through the $ method, and it will call the history method, so far what I've done is for example in the setLocation method it will return the old arguments and I will story them in my array Nx.history, but it's easier to factorise all of these "return" calls in the methods, and add a line to the $ method , that reads the name of the expected arguments of the method, and send it to the history method, so something like this :

$ : 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;
}


I'm not 100% sure what you're asking for - a way to extract the formal parameter names of a function?

I have no idea if this would work or not, but could you parse the string representation of the function to extract the parameter names?

It would probably be a very lame solution, but you might be able to do something like:

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


2.0

The idea with this newer version is to define the properties that you want to record for the object beforehand. It's a level of duplication, but it's only a one time thing. Then, in the constructor, create property setters for each of these properties. The setter does some side work along with setting the property. It pushes the arguments name and value onto a stack, and assigns the properties. The $ method is supposed to call dispatch the call to the appropriate method. Once the call is complete, the stack will be populated with the parameters that were set in that function. Pop off each parameter from that stack, until the stack is empty. Then call history with the method name, and the parameters that we just popped off the stack. Please let me know if this doesn't make any sense, I might have to word it better.

See an example here.

Here's a code example written in MooTools which is slightly similar to your Base class.

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

The arguments passed to a JavaScript function are accessible through an array-like object named arguments which is available for all functions.

When calling history, pass the arguments object to it.

a: function(a1, a2) {
    this.history.apply(this, arguments);
}

history will then be invoked as if it was called with two arguments with this being the base object - foo unless you call it with a different context.

I am not sure how Base plays into this. You would have to elaborate more as to the role of Base here.

Here' s a simple example:

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

Also note that although a has two named parameters here, we can still pass it any number of arguments, and all of them will be passed to the history method in turn. We could call a as:

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


Something like this should work. When you want to access the arguments that have been used you can loop through the foo.history array which contains the arguments list.

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

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

    history: []
};

I read your updated post. What do you mean by "names?" Variable names? For example, if someone called a(1337), would you want ["a1"] to be added to the array? And if a(1337, 132) was called ["a1", "a2"] would be added? I don't think there's any sane way to do that.

This is the best I can do. You will have to include a list of parameter names when defining your functions using the storeArgs function.

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: []
};

Let me know if it works.


This works in IE, but I'm not sure about other browsers...

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();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜