是否可以修改定义的 getter 函数?

Is it possible to modify defined getter function?

在微信小程序平台(javascript + 基于微信应用的原生混合)上做一个性能评估工具,我试图在它的原型中注入代码,例如 wx.request 函数.

这是您使用 wx.request 函数的方式:

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

所以为了在不手动编写添加所有锚点的情况下知道请求花费了多长时间,我尝试通过以下方式注入代码:

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

这失败了,我得到了一个 Cannot set property "prop" of #<Object> which has only a getter 错误。

所以我意识到对象的定义必须类似于:

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

所以我尝试了:

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

失败并出现错误 (request: fail parameter error: parameter.url should be String instead of Undefined)。然后我试了:

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

这不会引发错误,但在调用 wx.request()...

时也没有任何效果

您可以隐藏 request 函数。 简单示例:

隐藏getter:

// original getter latest
let base = {
  num: 1,
  get latest() {
    return this.num;
  }
}
console.log(base.latest);

// shadowing getter latest
Object.defineProperty(base, 'latest', {
  get: function() {
    return this.num + 1;
  }
});

console.log(base.latest);

对象的简单阴影 属性

// your original object
let base = {
    request(){
        console.log('request original');
    }
};

base.request()


base.request = () => {
    console.log('request new implementation');
};
 
// now shadow the original request implementation
base.request()

您可以通过重新定义 getter 来实现它。重点是:重新定义的 getter 应该 return 一个函数对象,因为 wx.request 是一个函数:

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

为什么我得到错误:request: fail parameter error: parameter.url should be String instead of Undefined?

您正在尝试访问 getter 本身的 argumentsget: function(){...} 中函数的 arguments)。这个arguments是一个空对象,可以通过console.log()语句来验证。因为它是空的,所以 arguments.url 是未定义的,这就是 wx 抱怨参数的原因。

这是一个工作示例:

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

以上代码将打印:

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