Javascript 有类似 Ruby 的 method_missing 功能吗?

IT技术 javascript ruby metaprogramming
2021-02-03 21:01:34

在 Ruby 中,我认为您可以调用尚未定义的方法,但仍可以捕获所调用方法的名称,并在运行时处理此方法。

Javascript 可以做同样的事情吗?

6个回答

method_missing不适合 JavaScript,原因与 Python 中不存在的原因相同:在两种语言中,方法只是碰巧是函数的属性;和对象通常具有不可调用的公共属性。与 Ruby 相比,对象的公共接口是 100% 的方法。

JavaScript 中需要的是一个钩子来捕获对缺失属性的访问,无论它们是否是方法。Python 有它:请参阅__getattr__特殊方法。

Mozilla__noSuchMethod__提议在充满它们的语言中引入了另一个不一致之处。

JavaScript 的前进方向是Proxy 机制(也在ECMAscript Harmony 中),它更接近于自定义属性访问的 Python 协议,而不是 Ruby 的method_missing

阿门:“ MozillanoSuchMethod提议在充满它们的语言中引入了另一种不一致。”
2021-03-16 21:01:34
请注意,与 Python 相比,Javascript 语义有点不同,也更棘手。在 Pythonf=obj.m;f(x)中相当于obj.m(x). 在 Javascript 中,obj.m(x)设置thisobj,而f=obj.m;f(x)没有。
2021-03-29 21:01:34
那时我不知道,但是 python 现在有一个非常方便的__missing__方法。
2021-03-30 21:01:34
__missing__方法仅用于映射,以添加逻辑来处理映射中缺少键的情况。例如,实现一个使用字符串键但不区分大小写的映射很有用。它与method_missing.
2021-04-10 21:01:34

您正在解释的 ruby​​ 功能称为“method_missing” http://rubylearning.com/satishtalim/ruby_method_missing.htm

这是一个全新的功能,仅存在于某些浏览器中,例如 Firefox(在蜘蛛猴 Javascript 引擎中)。在 SpiderMonkey 中,它被称为“__noSuchMethod__” https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/NoSuchMethod

请阅读 Yehuda Katz 的这篇文章http://yehudakatz.com/2008/08/18/method_missing-in-javascript/,了解有关即将实施的更多详细信息。

Yehuda Katz 的文章是 2008 年的,Brandon Eich从 2010 年就开始提倡 Proxy API Mozilla 提出__noSuchMethod__ API 是非标准的,没有未来。
2021-03-27 21:01:34
感谢我认为我会被我奇怪的问题困惑的文章 - 因为当我问元编程问题时我经常在这里:) - 我很高兴 js 大师考虑它。
2021-03-31 21:01:34

目前没有,没有。一个关于 ECMAScript Harmony 的提议,称为proxies,它实现了一个类似的(实际上,更强大的)功能,但是 ECMAScript Harmony 还没有出现,并且可能不会在几年内出现。

@HappyHamburger:我非常兴奋ES6,特别是适当的尾调用,let并且const,简洁的功能语法,并代理。
2021-03-18 21:01:34
@jörg-w-mittag,未来几乎就在这里:)
2021-03-22 21:01:34
代理目前在 Chrome 21 及以后的版本中使用实验性的 Javascript 标志实现。有关当前支持哪些 ECMAScript Harmony 功能的最新信息,请参阅此站点:kangax.github.io/es5-compat-table/es6
2021-03-28 21:01:34
@jörg-w-mittag - 您如何看待新规范中类的实现?
2021-04-03 21:01:34
@HappyHamburger:我更多地使用 ES 作为 Scheme 和 Self 的混合体,而不是浏览器内的 Java 克隆,所以我不太关心类。然而,由于它们只是语法糖,它们根本不会改变 ES 的核心。这与 ES4 类非常不同,ES4 类基本上是除原型之外的全新继承结构。
2021-04-03 21:01:34

我为 javascript 创建了一个库,让您可以method_missing在 javascript 中使用https : //github.com/ramadis/unmiss

它使用 ES6 代理来工作。这是一个使用 ES6 类继承的示例。但是,您也可以使用装饰器来实现相同的结果。

import { MethodMissingClass } from 'unmiss'

class Example extends MethodMissingClass {
    methodMissing(name, ...args) {
        console.log(`Method ${name} was called with arguments: ${args.join(' ')}`);
    }
}

const instance = new Example;
instance.what('is', 'this');

> Method what was called with arguments: is this

您可以使用Proxy类。

var myObj = {
    someAttr: 'foo'
};

var p = new Proxy(myObj, {
    get: function (target, methodOrAttributeName) {
        // target is the first argument passed into new Proxy, aka. target is myObj

        // First give the target a chance to handle it
        if (Object.keys(target).indexOf(methodOrAttributeName) !== -1) {
            return target[methodOrAttributeName];
        }

        // If the target did not have the method/attribute return whatever we want

        // Explicitly handle certain cases
        if (methodOrAttributeName === 'specialPants') {
            return 'trousers';
        }

        // return our generic method_missing function
        return function () {
            // Use the special "arguments" object to access a variable number arguments
            return 'For show, myObj.someAttr="' + target.someAttr + '" and "'
                   + methodOrAttributeName + '" called with: [' 
                   + Array.prototype.slice.call(arguments).join(',') + ']';
        }
    }
});

console.log(p.specialPants);
// outputs: trousers

console.log(p.unknownMethod('hi', 'bye', 'ok'));
// outputs: 
// For show, myObj.someAttr="foo" and "unknownMethod" called with: [hi,bye,ok]

关于

您将使用p代替myObj.

您应该小心,get因为它会拦截p. 因此,p.specialPants()会导致错误,因为specialPants返回的是字符串而不是函数。

真正发生的事情unknownMethod等同于以下内容:

var unk = p.unkownMethod;
unk('hi', 'bye', 'ok');

这是有效的,因为函数是 javascript 中的对象。

奖金

如果您知道期望的参数数量,则可以在返回的函数中将它们声明为正常的。
例如:

...
get: function (target, name) {
    return function(expectedArg1, expectedArg2) {
...