Подтвердить что ты не робот

JavaScript эквивалент PHP __call

В PHP вы можете обнаружить, когда метод вызывается, даже если он не существует, используя функцию "magic" __call.

public function __call($methodName, $args)
{
    // do something
}

Вы можете вызвать любой метод, и имя и аргументы передаются этому волшебному catch-all.

Есть ли аналогичный метод в JavaScript, который позволил бы вызывать любой метод, даже если он на самом деле не существовал на объекте?

var foo = (function () {
    return {
         __call: function (name, args) { // NOT REAL CODE
             alert(name); // "nonExistent"
         }
    }
}());

foo.nonExistent();
4b9b3361

Ответ 1

It is возможно с использованием ESA Proxy API:

var myObj = {};
var myProxy = new Proxy(myObj, {
  get: function get(target, name) {
    return function wrapper() {
      var args = Array.prototype.slice.call(arguments);
      console.log(args[0]);
      return "returns: " + args[0];
    }
  }
});
console.log(myProxy.foo('bar'));

Ответ 3

Нет. Из-за того, как работает JavaScript, эквивалент будет похож на Python __getattr__/__getitem__, а не на PHP __call, поскольку его нужно будет обрабатывать при извлечении атрибута, а не при его вызове.

Затем вы можете посмотреть на вопрос типа Python __getattr__ в Javascript, который отвечает на него таким образом.

См. также такие вопросы, как:

Ответ 4

Чтобы немного ответить на ответ @amirnissim.

Как известно, большинство из нас уже знают, ES6 представляет Proxy API, который позволяет нам создать объект (объект Proxy), который перехватывает вызовы этому объекту, посредством чего нам предоставляется возможность "маршрутизировать" атрибут, который пользователь вызывал на объект, может пожелать.

Восхищение магических методов PHP

Нет никакого способа расширить класс, используя объект Proxy, но мы можем сделать промежуточный шаг для превращения объекта в прокси-сервер и маршрутизировать любые входящие вызовы метода методу, доступному самому объекту

  класс MyProxy
{   конструктор()   {       return this.asProxy()   }
   /**    * Возвращайтесь как прокси с этим объектом в качестве цели.    */   asProxy()   {       пусть обработчик = {           /**            * Эта функция вызывается всякий раз, когда любое свойство на прокси-сервере            * называется.            *            * @param нацеливается на "родительский" объект; объект прокси            * виртуализирует            * @param поддерживает свойство, называемое прокси-сервером            */           get: function (target, prop)           {               /* Это вернет свойство на родительский объект                */               if (typeof target [prop]! == 'undefined')                   return target [prop]
               //TODO: реализовать пользовательскую логику           }       }
       вернуть новый прокси (это, обработчик)   }
}
Код>

Это по сути дает вам ту же функциональность, что и магия PHP __ get и метод __ call. Что касается версии __ call, мы просто возвращаем функцию для ввода пользователем аргументов.

Демонстрация выше

Чтобы использовать это, давайте сначала добавим немного пользовательской логики в место, где находится TODO: реализовать пользовательскую логику:

  if (prop === 'helloWorld')   return function() {console.log( "Привет, мир!" )}
еще   return function() {console.log( "Где ты, привет мир?" )}
Код>

Если мы продолжим и создаем новый экземпляр класса MyProxy, мы можем запустить пользовательскую логику, которую мы реализовали:

  let myProxy = new MyProxy()

myProxy.test()
myProxy.hello()
myProxy.helloWorld()
Код>

Вышеприведенный пример выводит:

Где ты, привет мир?
Где ты, привет мир?
Привет, мир!

Конечно, было бы возможно вернуть любой другой тип значения из функции get, мы могли бы также вернуть строку или целое число.

Простота использования; Использование через наследование

Чтобы сделать это еще проще в использовании, могу ли я предложить обернуть метод asProxy в другой класс, а затем просто расширить любой класс, который нуждается в функциональности "магического метода" с классом, содержащим asProxy? Просто вернув метод asProxy из конструктора, вы в основном получили те же функции, что и в PHP, в JavaScript.

Конечно, было бы также необходимо, чтобы метод get был несколько редактируемым, так что пользовательская логика все еще может обрабатываться из подкласса. Возможно, отправив замыкание на вернуть this.asProxy(() = > {}), который затем вызывается из самой функции get? Или, возможно, даже маршрутизируйте функцию get в метод get, присутствующий в объекте target?

Имейте в виду, однако, это применимо только в ES6. Транспилеры, такие как Babel, не могут, и цитирую:

Из-за ограничений ES5, Прокси не могут быть переписаны или заполированы.

Решение, представленное выше, тем не менее работает отлично, если это условие выполнено. Это, например, вполне жизнеспособный вариант в Node.js.

Ответ 5

Хотя это не изящный способ, как мы уже определили, что JavaScript не имеет __call, method_missing, __getattr__, можно создавать комбинации свойств для создания конкретных функций, которые ретранслируют один метод, передавая свойства, которые были использованы для его создания.

Одним из примеров является Myriad.js.