#48 间谍活动


  • 0
    administrators

    国家有重要的任务要托付给你:完成间谍函数 spy,它可以潜伏到任何一个函数当中,监听它们的所有活动。spy 接受一个函数作为参数,返回一个被间谍潜伏以后的函数。

    let america = (a, b) => a + b
    
    america = spy(america)
    america(1, 2) // => 3
    

    spy 返回的函数和原来的函数的功能一样,但是它悄悄记录了每一次执行的参数和执行结果,都存放到一个 calls 数组里面:

    america(1, 2)
    america(3, 4)
    
    america.calls[0].args // => [1, 2]
    america.calls[0].result // => 3
    
    america.calls[1].args // => [3, 4]
    america.calls[1].result // => 7
    

    注意,spy 可以支持潜伏到对象方法当中:

    let user = {
      name: 'Jerry',
      getName () {
        return this.name
      }
    }
    
    user.getName = spy(user.getName)
    user.getName() // => 'Jerry'
    user.getName.calls[0].result // => 'Jerry'
    

    另外,不要修改被 spy 的函数(你应该返回一个全新的函数),否则会被敌人发现。


  • 0

    用了比较简单的实现过了,感觉测试还不是很完善。能通过的代码在潜入前 america.money === 9999,潜入 spy 以后 america.money === undefined 了。


  • 0
    administrators

    @Sunjourney 没做太严格限制。刚改了一下,现在应该已经通不过了。


  • 0

    @胡子大哈 注释还可改一下,小笔误

    america(1, 2) // => 2
    

  • 0
    管理员

    这道题告诉了我一个道理:有时候还是旧鞋穿着舒服啊~
    本来我写好了代码

    const spy = fn => {
      let calls = []
      let f = (...args) => {
        let obj = {
          args: args,
          result: fn(...args)
        }
        calls.push(obj)
        return fn(...args)
      }
      f.calls = calls
      return f
    }
    

    这代码是有问题的,当fn是对象方法的时候,想尽了一切办法都不能把对象的this绑进去,因为箭头函数的this始终是window。
    箭头函数很酷,但是这里不得不放弃他了。。
    还是用老伙伴吧~

    const spy = function(fn) {
      var calls = []
      var f = function() { 
        var obj = {
          args: [...arguments],
          result: fn.apply(this, arguments)
        }
        calls.push(obj)
        return obj.result
      }
      f.calls = calls
      return f
    }
    

  • 0
    administrators

    @陈小俊 哈哈,👍赞分享。

    这里确实是个陷阱,尖头函数的 this 指向被定义的时候所在的作用域的 this 而不随着调用者的改变而改变,所以这里还是得用老方法才可以达到题目的效果。也有不少朋友进了这个坑。

    总结一下又是一个进步。


  • 1
    管理员

    @胡子大哈 前人填坑,后人享福


  • 0

    这破题最ES6的解法应该是这个

    const spy = (fn, calls = []) => new Proxy(fn, {
      get(target, prop) {
        if (prop === 'calls') return calls
        return prop[prop]
      },
      apply(target, thisArg, args) {
        const result = target.apply(thisArg, args)
        calls.push({args, result})
        return result
      }
    })
    

  • 0

    为什么我这么写显示不对啊,说没有用calls记录行为

    const spy = (fn) => {
      return function b(){
        b.calls=b.calls||[]
        let res=fn.apply(this,arguments)
        b.calls.push({args:[...arguments],result:res})
        return res
      }
    }
    

  • 0
    administrators

    @physihan 这样改:

    const spy = (fn) => {
      const calls = []
      function b(){
        let res=fn.apply(this,arguments)
        b.calls.push({args:[...arguments],result:res})
        return res
      }
      b.calls = calls
      return b
    }
    

  • 0

    @胡子大哈 好吧,在里面写不行啊,我估计我这样写函数没调用是不能获取到calls属性的,谢谢了


  • 0

    此回复已被删除!

  • 0

    哇,充了会员看了半天.也没知道我怎么错的.这this

    const spy = (fn) => {
      function spyFn(){
        //执行方法
        params = Array.prototype.slice.call(arguments)
        let result = fn.bind(this)(...params); 
        //记录
        spyFn.calls.push({
          args:params,
          result:result
        })
        return result;
      }
      spyFn.calls = [];
      return spyFn
    }
    

登录后回复
 

与 ScriptOJ 的连接断开,我们正在尝试重连,请耐心等待