Aero Wang Aero Wang - 2 months ago 19
Javascript Question

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()
...

Answer Source

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