Можно ли написать функцию, которая применяется к каждому имени? - PullRequest
3 голосов
/ 23 мая 2019

Можно ли предоставить функцию объекту, который всегда вызывается при вызове функции независимо от имени?

Или другими словами: возможно ли иметь функцию, которая применяется ко всем возможным именам?

Может быть, с некоторыми изменениями в объекте prototype?

Вот пример того, как это должно работать:

const o = {
  [magic here]: () => 1;
};

o.foo(); // returns 1
o.bar(); // returns 1
o.baz(); // returns 1

Изменить для пояснения, почему я хочу сделать это:

Я экспериментирую с железнодорожным программированием. По сути, вместо ручной проверки, является ли объект null или undefined и соответствующей реакции, я хочу, чтобы это было автоматизировано.

Пример:


// checks if object is null and returns a object, that can be called however without crashing
// thanks to T.J. Crowder's answer
function saveNull(o){
  if(o !== null) return o;

  const p = new Proxy({}, {
    get(target, prop, receiver) {
      return () => p;
    },
  });

  return p;
}

const a = " abc"; // could be null

const b = a.toUpperCase().trim(); // could crash
const c = a ? a.toUpperCase.trim() : null; // approach 1
const d = a && a.toUpperCase().trim(); // approach 2
const e = saveNull(a).toUpperCase().trim(); // approach 3

Мне кажется, что последний подход более читабелен и интересен для экспериментов.

1 Ответ

10 голосов
/ 23 мая 2019

Вы можете сделать это с помощью Proxy в ES2015 и выше;вы не можете сделать это в ES5 и ниже.

Если вы действительно хотите, чтобы каждое возможное свойство возвращало эту магическую функцию, то это довольно просто:

const obj = {};
const magic = () => 1;
const p = new Proxy(obj, {
  get(target, prop, receiver) {
    return magic;
  }
});

console.log(p.foo());     // returns 1
console.log(p.bar());     // returns 1
console.log(p.baz());     // returns 1

Если вы хотите, чтобы объект имел другие свойства, и возвращали их значения, если они есть, но магическую функцию, если нет, вы должны использовать Reflect.has, чтобы увидеть, есть ли у объекта свойство, а затем Reflect.get, чтобы получить его, если так:

const obj = {
  notMagic: 42
};
const magic = () => 1;
const p = new Proxy(obj, {
  get(target, prop, receiver) {
    // If the object actually has the property, return its value
    if (Reflect.has(target, prop)) {
      return Reflect.get(target, prop, receiver);
    }
    // Return the magic function
    return magic;
  }
});

console.log(p.foo());     // returns 1
console.log(p.bar());     // returns 1
console.log(p.baz());     // returns 1
console.log(p.notMagic);  // 42

Если бы вы хотели, чтобы функция видела this в качестве объекта, вы бы использовали функцию без стрелки и, вероятно, bind, чтобы упростить задачу:

const obj = {
  notMagic: 42
};
const magic = function() {
  console.log(this === obj);
  return 1;
}.bind(obj);
const p = new Proxy(obj, {
  get(target, prop, receiver) {
    // If the object actually has the property, return its value
    if (Reflect.has(target, prop)) {
      return Reflect.get(target, prop, receiver);
    }
    // Return the magic function
    return magic;
  }
});

console.log(p.foo());     // returns 1
console.log(p.bar());     // returns 1
console.log(p.baz());     // returns 1
console.log(p.notMagic);  // 42
...