Search code examples
javascriptwechat

Is it possible to modify defined getter function?


Working on a performance reviewing tool on wechat mini apps platform (javascript + native hybrid based on wechat app), I am trying to inject codes into its prototypes, for example the wx.request function.

This is how you would use a wx.request function:

wx.request({
  url: 'test.php',
  data: {
     x: '' ,
     y: ''
  },
  header: {
      'content-type': 'application/json'
  },
  success: function(res) {
    console.log(res.data)
  }
})

So in order to know how long the request has taken without manually writing adding all the anchors, I tried to inject code by:

var owxrequest = wx.request
wx.request = function() {
  console.log('test', Date.now())
  return owxrequest.apply(owxrequest, arguments)
}

This failed and I got an Cannot set property "prop" of #<Object> which has only a getter error.

So I realized the the object must have been defined similar to:

wx = {
  request: get function(){
    ...
  }
  ...
}

So I tried:

var owxrequest = wx.request
Object.defineProperty(wx, 'request', {
  get: function() {
    console.log('test', Date.now())
    return owxrequest.apply(owxrequest, arguments)
  }
})

This failed with an error (request: fail parameter error: parameter.url should be String instead of Undefined). Then I tried:

var owxrequest = wx.request
Object.defineProperty(wx, 'request', {
  set: function() {
    console.log('test', Date.now())
    return owxrequest.apply(owxrequest, arguments)
  }
})

This wouldn't throw an error but it also has no effect when calling wx.request()...


Solution

  • You can implement this by re-define the getter. The point is: the re-defined getter should return a function object, as wx.request is a function:

    Object.defineProperty(wx, 'request', {
      get: function() {
        return function() {
          //...
        };
      }
    });
    

    Why I get the error: request: fail parameter error: parameter.url should be String instead of Undefined?

    You are trying to access the arguments of the getter itself (the arguments of function in get: function(){...}). This arguments is an empty object and it can be verified by console.log() statement. As it is empty, arguments.url is undefined, that's why wx complains about the parameter.

    Here is an working example:

    let wx = {
      get request(){
        return function() {
          console.log(10);
          return 88;
        };
      }
    };
    
    let oldF = wx.request;
    
    Object.defineProperty(wx, 'request', {
      get: function() {
        return function() {
          console.log(new Date());
          return oldF.apply(wx, arguments);
        };
      }
    });
    
    console.log(wx.request());
    

    The above code would print:

    2017-08-28T06:14:15.583Z // timestamp
    10
    88