【问题标题】:Javascript (ECMA-6) class magic method __call like PHPJavascript (ECMA-6) 类魔术方法 __call 像 PHP
【发布时间】:2017-02-15 08:36:49
【问题描述】:

这是我的用例

getSomeFields(persons, fields){

    let personsWithSpecificFields = [];

    _.each(persons, (person) => {

        let personSpecificFields = {};

        _.each(fields, (field) => {
            // here im thinking to modify the field to match the method name 
            // ( if something like __call as in php is available)
            // e.g. field is first_name and i want to change it to getFirstName
            personSpecificFields[field] = person[field]();

        });

        personsWithSpecificFields.push(personSpecificFields);
    });

    return personsWithSpecificFields;
}

这是我的person class

import _ from 'lodash';

export default class Person{

    // not working..
    __noSuchMethod__(funcName, args){
        alert(funcName);
    }

    constructor( data ){
        this.init(data);
    }

    init(data) {
        _.each(data, (value, key) => {
           this[key] = value;
        });
    }
}

我已经通过Monitor All JavaScript Object Properties (magic getters and setters),尝试实现这个JavaScript getter for all properties,但没有运气。

我知道我可以通过编写另一个方法来做到这一点,它将我的first_name 转换为getFirstName 并试一试。但是有什么方法可以像在课堂上那样以ECMA-6 的方式做到这一点。

谢谢。

【问题讨论】:

  • 对象实例就是任何对象。函数是对象。因此,函数也可以具有属性,也可以是其他方法。如果你想要一个“可调用对象”,就让它成为一个函数。
  • 好:您搜索了其他解决方案。不好:您找到了一个并在第一个答案后停止阅读。无论如何,当您使用 ES6 时,请尝试 Proxy 解决方案。
  • @Boldewyn 让我试试,先生,
  • mdn: NoSuchMethod 已过时

标签: javascript ecmascript-6


【解决方案1】:

您可以使用proxy 来检测对您的对象没有的属性的访问并处理它——这接近于PHP 的__call

var person = new Person();
// Wrap the object in a proxy
var person = new Proxy(person, {
    get: function(person, field) {
        if (field in person) return person[field]; // normal case
        console.log("Access to non-existent property '" + field + "'");
        // Check some particular cases:
        if (field == 'first_name') return person.getFirstName;
        // ...
        // Or other cases:
        return function () {
            // This function will be executed when property is accessed as a function
        }
    }
});

你甚至可以在你的类的构造函数中这样做:

class Person {
    constructor(data) {
        this.init(data);
        return new Proxy(this, {
            get: function(person, field) {
                if (field in person) return person[field]; // normal case
                console.log("Access to non-existent property '" + field + "'");
                // Check some particular cases:
                if (field == 'first_name') return person.getFirstName;
                // ...
                // Or other cases:
                return function () {
                    // This function will be executed when property is accessed as a function
                    return 15; // example
                }
            }
        });
    }
    // other methods ...
    //
}

代理的好处是返回的对象仍然被认为是原始类的实例。使用上面的代码,以下将是正确的:

new Person() instanceof Person

【讨论】:

  • 先生,get 对字段工作正常,但对方法不工作
  • 它也适用于方法,但注意不要在代理中调用它们,而是只返回一个函数引用。例如,请注意我在示例代码中没有在 person.getFirstName 之后添加括号。方法本质上也是属性,它们恰好是函数类型。
【解决方案2】:

Javascript 中没有像 PHP 那样特殊的 __methods(),所以你只有 getterssetterstoString()valueOf()

您可以试一试Object.defineProperty(),因为这样您就可以像这样动态创建getter:

Object.defineProperty(obj, 'first_name', {
   get: function () { return … }
});

mdn

结果类似于:

var obj = {
  get first_name () { return … }
}

如果你需要调用一个对象的方法,你也可以这样做:

var prop = 'getFirstName',
    result = obj[prop]();

for 循环中也可以做些什么。

【讨论】:

  • 还有toJSON for JSON.stringify
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-17
  • 1970-01-01
  • 1970-01-01
  • 2019-12-04
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
相关资源
最近更新 更多