永无止境的对象
#javascript #调试 #proxy

最近我一直在弄乱Proxy对象,并且我创建了一个非常简单的代理,可以建立一个永无止境的对象链。它基本上是No operations的链条,是的,我知道这很难卖,但是我用它来重新点燃我的一个旧项目,它可以像Optional chaining (koude0)一样起作用(很小),所以我想我会分享。

执行

这是一个很小的代理,带有 [[ProxyHandler]] 捕获[[Get]][[Call]],它只是在每个陷阱中返回代理对象本身:

const neverendingObject = new Proxy(function () { }, {
  apply: function () { return neverendingObject; },
  get: function () { return neverendingObject; }
});

注意 [[[ProxyTarget]] 是一个函数,这将允许neverendingObject()函数调用而无需任何额外的链接。

出于教育目的,我将在陷阱中添加登录,这样就更容易获得发生的事情:

const neverendingObject = new Proxy(function () { }, {
  apply: function (target) { console.log('[[Call]] ()'); return neverendingObject; },
  get: function (target, prop) { console.log('[[Get]]', prop); return neverendingObject; }
});

neverendingObject.aProperty.aFunction().aProperty

// [[Get]] aProperty
// [[Get]] aFunction
// [[Call]] ()
// [[Get]] aProperty

怎么运行的

我在apply零件周围缠绕头时遇到了一些困难,额外的get呼叫首先获得对aFunction的引用,然后呼叫。




我在下面包含了呼叫链,突出显示了这一路的每个步骤,这样就对我有所帮助(请记住,每个 [[get]] [[call]] 将返回neverendingObject对象)。

    kouude5 [[get]] appoperty

  1. neverendingObject.aProperty [[get]] afunction

  2. neverendingObject.aProperty.aFunction [[call]] ()

    neverendingObject.aProperty.aFunction() [get]]

  3. neverendingObject.aProperty.aFunction().aProperty

希望这不会增加任何混乱。

可选的链接(?.)盒

neverendingObject无法替换?.操作员,但是可以在不测试每个步骤的情况下模仿链接的行为。但是,只有最后一个动作是一个函数,是的,这是大多数用例的表演者。

const person = {
  arms(hasNoArms) {
    if (hasNoArms === true) {
      return neverendingObject
    } 

    return {
      wave() { console.log('Waving arms'); }
    };
  }
}

person.arms().wave(); // "Waving arms"
person.arms(true).wave(); // Nothing happens

使用?.运算符,它看起来像以下内容(假设返回null而不是neverendingObject,当设置了hasNoArms参数时):

person.arms(true)?.wave(); // Nothing happens

?.操作员更加明确,这将是大多数情况下选择的首选方法。作为奖励,?.操作员停止执行链的其余部分,其中neverendingObject将需要将链条运行到尽头,包括任何昂贵的计算作为参数。

实际用例

有了一切,neverendingObject是错误的,我发现了一个用例,它在现有对象中添加了有条件的链条。

一个非常简单的情况是将and函数添加到console对象中,仅当条件是true时,就可以轻松地进行记录输出,而没有添加的情况。

console.and = function (condition) {
  if (condition) {
    return console;
  }
  return neverendingObject;
}

console.and(1 == 1).log('is logged'); // "is logged"
console.and(1 == 2).log('is logged'); // Nothing happens

结论

让我们将简单的ifand()函数进行比较:

if (isDebugging) {
  console.log('Some message');
}

// vs

console.and(isDebugging).log('some message');

它节省了几行,并且(主观上)易于阅读。当使用time()timeEnd()进行一些灯光分析时,这几行加起来:

if (isDebugging) {
  console.time('abcd');
}
// Expensive stuff
if (isDebugging) {
  console.timeEnd('abcd');
}

// vs

console.and(isDebugging).time('abcd');
// Expensive stuff
console.and(isDebugging).timeEnd('abcd');

我已经开始了一个旧项目的新分支:ConditionalConsole

以前的版本需要创建另一个对象,而不是console。使用此技术,我可以装饰它并使功能具有更本地的感觉。