Javascript无限关卡

时间:2019-09-16 19:05:51

标签: javascript currying

最近,我认为我发现的一些代码称为currying。 代码如下:

layer.components[0]("ADBE Propety1")("ADBE Property 2")("ADBE Property 3");

我感兴趣的复制部分是components[0]之后的多组括号。咖喱对我来说是新的(到目前为止),关闭可能会变得很复杂。所以我需要一些帮助。

我想创建一个该类的实例有孩子的类,并且我可以这样命名孩子:

let bins = new Bins(proj);
console.log(bins('Videos')('More')('NiteLite_90.mp4')); 
// Return: {name: 'NiteLite_90.mp4', children: []}

使用下面的代码,我可以深入两层(降至“更多”),但不能超过此水平。我希望能够深入无限。

class Bins {
  constructor(proj) {
    this.bins = this._getBins(proj);
  }

  bin(name) {
    let bin = this.bins.filter(b => b.name === name)[0];
    if (bin) {
      return (name) => bin.children.filter(b => b.name === name)[0];
    } else {
      return null;
    }
  }

  _getBins(proj) {
    let { children } = proj;
    let childs = [];
    let self = this;
    children.forEach(child => {
      let obj = { name: child.name };
      if (child.children && child.children.length > 0) {
        obj.children = self._getChildren(child);
      }
      childs.push(obj);
    });
    return childs;
  }

  _getChildren(child) {
    let children = [];
    let self = this;
    child.children.forEach(c => {
      let obj = { name: c.name };
      if (c.children && c.children.length > 0) {
        obj.children = self._getChildren(c);
      }
      children.push(obj);
    });
    return children;
  }
}

let proj = {
  children: [
    {
      name: 'Videos',
      children: [
        {
          name: 'NiteLite_00.mp4',
          children: []
        },
        {
          name: 'More',
          children: [
            {
              name: 'NiteLite_90.mp4',
              chidlren: []
            }
          ]
        },
        {
          name: 'NiteLite_97.mp4',
          children: []
        }
      ]
    },
    {
      name: 'Sequences',
      children: [
        {
          name: 'Oregon Coast',
          children: []
        }
      ]
    },
    { name: 'Music', children: [] },
  ]
};
let bins = new Bins(proj);
console.log(bins.bin('Videos')('More')('NiteLite_90.mp4')); // I don't want to have to call `.bins` first

我可以在设置方面获得一些帮助吗? 我在这里研究了多个其他易引起争议的帖子,并看到了一些有关它的博客,但是我仍然没有得到它,我想要一些有关代码的特定帮助。

3 个答案:

答案 0 :(得分:2)

您可以具有递归咖喱功能,以便能够深入所需的内容。但是您还有另一个问题:您如何知道何时停止返回函数并返回实际对象?

如果调用bins.bin('Video')('More') -您如何知道要返回More对象的bin还是要搜索More的子代的函数,以便您查找'NiteLite_90.mp4垃圾箱?

以下是一种可能的解决方案,将为您提供两种选择:

class Bins {
  search(collection, name) {
    const bin = collection.find(b => b.name === name);
    if (bin) {
      // first create a function that will search through this bin's children
      const curry = (name) => this.search(bin.children, name);

      // but make the bin itself available through a `.bin` property on the function
      curry.bin = bin;

      // return this new function so it can be curried
      return curry;
    } else {
      return null;
    }
  }

  bin(name) {
    return this.search(this.bins, name);
  }

  // plus everything you already have in this class, except for the original
  // bin(name) function
}

现在,您可以进入无限多个级别,还可以通过.bin属性访问任何中间容器:

let bins = new Bins(proj);

console.log(bins.bin('Videos').bin);
// { name: "Videos", children: [ ... ] }

console.log(bins.bin('Videos')('More').bin);
// { name: "More", children: [ ... ] }

console.log(bins.bin('Videos')('More')('NiteLite_90.mp4').bin);
// { name: "NiteLite_90.mp4" }

与原始方法一样,search方法可以返回null,因此在搜索可能不存在的路径时请多加注意:

console.log(bins.bin('Videos')('DoesNotExist')('NiteLite_90.mp4').bin);
// Uncaught TypeError: bins.bin(...)(...) is not a function

console.log(bins.bin('Videos')('More')('DoesNotExist.mp4').bin);
// Uncaught TypeError: Cannot read property 'bin' of null

因此,为了安全起见,您可能希望将此类调用包装在try/catch

let bin;
try {
  bin = bins.bin('Videos')('DoesNotExist')('NiteLite_90.mp4').bin;
} catch (e) {
  console.error('Bin not found!');
}

if (bin) {
  // do whatever you want with the found bin
}

答案 1 :(得分:0)

只需创建一个函数,该函数将返回自身:

class Foo{
  constructor(){
    function bar(){
      //Do something nice here
      return bar
    }
    this.bar=bar
  }
}

new Foo().bar(1)(2)(3)

现在,您可以无限深入……

new Foo().bar(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)(13)(14)(15)(16)(17)(18)(19)(20) //Works perfectly 

好,但是如何收集所有通话的数据?

这是开始变得棘手的地方。

  1. 您可以在每次调用函数的“所有者”对象后存储一些东西:
class Foo{
  constructor(){
    function bar(arg){
      baz.push(arg)
      return bar
    }
    const baz=[]
    this.bar=bar
    this.baz=baz
  }
}

const foo=new Foo()
foo.bar(1)(2)(3)

console.log(foo.baz) //[1,2,3]
  1. 或者,通过bind this到返回的函数,在后续调用之间传递一些信息,如下所示:
class Foo{
  constructor(){
    function bar(...args){
      console.log(this)
      return bar.bind(
        this //Bound array
        .concat(args)
      )
    }
    this.bar=bar.bind([])
  }
}

new Foo().bar(1)(2)(3)()
//[]
//[1]
//[1,2]
//[1,2,3]

答案 2 :(得分:-1)

这是您要找的东西吗?

class Animal {
  constructor (name) {
    console.log(`Im a bear called ${name}`)
  }

  shout (voice) {
    return (sound) => `I am making a ${sound} sound with a ${voice} voice` ;
  }
}

const harry = new Animal('Harry')
const speakUp = harry.shout('low')('woof')

console.log(speakUp)

小解释

currying的整个想法是函数返回函数。因此,尽管您通常会执行以下操作:

const hello = (name, age, job) => (
  `My nam is ${name}, I am ${age} and I do ${job} for a living`
)

通过招惹你会做类似的事情:

const hello = (name, age, job) => (
  `My nam is ${name}, I am ${age} and I do ${job} for a living`
)

const helloWithCurrying = (name) => (age) => (job) => (
  `My nam is ${name}, I am ${age} and I do ${job} for a living`
)

console.log(hello('Rick', 26, 'coding'))
console.log(helloWithCurrying('Rick')(26)('coding'))

当您具有复杂的高阶函数时,curry的好处真正发挥了作用。