JavaScript相当于C#的DynamicObject?

时间:2012-08-27 22:34:51

标签: c# javascript

为了清楚起见,继承DynamicObject的类(当然是在C#中)与JavaScript的变量是动态的概念不同。 DynamicObject允许实现者以编程方式确定对象具有哪些成员,包括方法。

编辑:我了解JavaScript对象可以在运行时添加任何成员。这根本不是我所说的。这是一个C#示例,显示了DynamicObject的功能:

public class SampleObject : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = binder.Name;
        return true;
    }
}

dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".

当访问obj的成员时,它使用TryGetMember以编程方式确定成员是否存在以及它的值是什么。简而言之,成员的存在是在请求时确定的,而不是通过事先添加它来确定的。我希望这可以澄清一下这个问题。如果您想知道,我正在尝试确定是否可以在JavaScript中创建一个对象,当它使用函数调用语法时如下:

myAPI.uploadSomeData(data1, data2)

uploadSomeData调用转到类似函数的“TryGetMember”,它使用名称“uploadSomeData”执行$ .ajax调用以生成URL,返回值为结果。

4 个答案:

答案 0 :(得分:2)

令人惊讶的是,经过几周的偶尔的JavaScript研究,我找到了两个答案:

ES6 Proxies

noSuchMethod

答案 1 :(得分:1)

JavaScript允许在for...in循环中迭代对象的属性和方法。 您可以使用typeof运算符确定它是一种方法。

<强> HTML:

<ul id="console"></ul>​

<强> JavaScript的:

var Application = (function(app) {
    app.constants = app.constants || {};
    app.constants.PRINT_OBJ_TITLE = '[Printing an object]';

    app.console = {
        constants: {
            SEPARATOR: new Array(50).join('-')
        },
        output: document.getElementById('console'),
        log: function() {
            var li = document.createElement('li');
            li.innerHTML = Array.prototype.join.call(arguments, '');
            this.output.appendChild(li);
        },
        printSeparator: function() {
            this.log(this.constants.SEPARATOR);
        }
    };

    app.printObj = function(obj) {
        this.console.log(app.constants.PRINT_OBJ_TITLE);
        for(var prop in obj) {
            if(obj.hasOwnProperty(prop)) {
                var propType = (typeof obj[prop] == 'function')
                    ? 'function'
                    : 'property';
                this.console.log(propType, ': ', prop);
            }
        }
        this.console.printSeparator();
    };

    return app;
})(Application || {});


var obj = {},
    app = Application;

obj.foo = function() {
    alert("I'm a foo function!");
};

obj.bar = "I'm just a property";

app.printObj(obj);​

DEMO

<强>更新

所以你不应该期望JavaScript有如Java或C#那样的大量反射工具。 您可以通过某种方式模拟此类行为,但无论如何,您将无法创建特殊的JavaScript对象并调用其不存在的属性。唯一的方法是创建一个特殊的功能,实现开关,外观,地图等 - 任何允许使流动更动态的结构。

像这样exmaple

您可以改进此逻辑并根据用户的操作,传入数据等动态向app.Stuff添加其他属性和功能。因此,总体而言,您可以使用某种元构建智能灵活的系统 - 用JavaScript编程。

答案 2 :(得分:1)

我堆满了类似的问题,并写下了这段代码:

   const dynamicFunc = (input) => {
        const handler = {
            get: (obj, prop) => {

                // edge case when .toString() is calling for dynamic prop - just return any string
                if (typeof prop === 'symbol') {
                    return () => "custom_dynamic_str";
                }

                const isPropExist = typeof obj[prop] !== 'undefined';

                if (isPropExist) {
                    const val = obj[prop];

                    // for case, when we assigned our function to dynamic object, we should return it
                    if (val.__isSetAsFunction) {
                        return val.func;
                    }

                    // if value was created not by this method - return value
                    if (!val.__isDynamic) {
                        return val;
                    }

                    // function - our created dynamic func, let's create next chain part
                    if (typeof val === 'function') {
                        return dynamicFunc(val);
                    }

                    return val;
                }
                obj[prop] = () => dynamicFunc({});
                obj[prop].__isDynamic = true;
                return dynamicFunc(obj[prop]);
            },
            set(target, prop, value) {
                //  if our custom function was set to dynamic
                if (typeof value === 'function') {
                    // wrap it to unwrap in get
                    target[prop] =
                        {
                            __isSetAsFunction: true,
                            func: value
                        };
                }
                else {
                    target[prop] = value;
                }
                return true;
            },
            apply: function (target, thisArg, argumentsList) {
                return dynamicFunc({});
            }
        };

        let proxy = new Proxy(input, handler);
        return proxy;
    };
    return dynamicFunc(baseObj);

我在这里使用Proxy类作为基本解决方案,所以用两个词来说-每次尝试访问某个属性时,如果此属性尚不存在,它将创建该属性。是时候进行编辑了,因为我堆满了问题,需要解决这些问题,所以:)

示例:

let ob = dynamic();
ob.test1.test2.test3('hello from Belarus!','qwerty').test5.t('test');

//we could assign properties on the fly : 
ob.myProp.pyProp2 = 2;

console.log(ob.myProp.pyProp2) // "1" will be outputed

// some tests using chai and chai-spies: 
    dynamic().genericProperties.anyFunc().myprop.test();
    let obj = dynamic({ predefinedObjValue: 3 });
    obj.prop1.prop2.test = 1;
    obj.prop1.prop3.test = 2;
    obj.prop2.myfunc = () => { };

    expect(obj.prop1.prop2.test).to.be.equal(1);
    expect(obj.prop1.prop3.test).to.be.equal(2);
    expect(obj.predefinedObjValue).to.be.equal(3);

    const myFuncSpy = chai.spy.on(obj.prop2, 'myfunc');
    obj.prop2.myfunc();
    expect(myFuncSpy).to.have.been.called();

,不会导致任何错误 另外,您可以定义自己的基础对象,并且不会被覆盖:

let ob = dynamic({mycustomProp : 1});
ob.test1.test2.test3('asdasd','tt').test5.t('test'); //without error

console.log(ob.mycustomProp) // "1" will be outputed    

工作示例:https://codesandbox.io/s/cranky-liskov-myf65

答案 3 :(得分:0)

编辑1: 您可以使用typeof检查方法是否存在:     if(typeof(obj.methodName)!=“undefined”){     //调用methodName     } 如果要专门检查函数,其类型将返回“function”。但是,我不知道有什么方法可以获得函数的签名,尽管如果你的函数很好地处理空值,JavaScript是相当宽容的。

原始答案 我相信Ethan Brown有这个权利,因为所有Javascript对象基本上只是变量的名称 - 值对,有时是函数。请尝试以下代码来警告任何给定对象的所有属性和方法的列表:

function obj(prop){
    this.prop = prop;
    this.setProp = function setProp(prop){this.prop = prop};
                                         }
        var myObj = new obj("something");
    myObj.setProp("anything else");
var getKeys = function(obj){
    var keys = [];
   for(var key in obj){
      keys.push(key);
   }
   return keys;
}
alert(getKeys(myObj));

请注意,这与Slashnick在How to list the properties of a JavaScript object中使用的程序相同