使用.apply()函数返回函数时,从callback函数更新“this”

我有一个ProjectClient类,它包含一个用于进行HTTP调用的方法( .GET() )。 它以与节点请求相同的方式支持一些参数和callback,但是也有一些复杂的url和header构build函数在幕后发生:

 client.GET(idOrDataObject, function(err, customResponse) { // url is built based on the id or dataObject passed as the first param }) 

在成功的响应中,返回的对象types之一是一个DataObject

 client.GET(idOrDataObject, function(err, customResponse) { console.log(customResponse.dataObject instanceof DataObject) // true }) 

我向DataObject类中添加了一个名为reload()的便捷方法,该方法调用client.GET()方法并重新加载,但是我希望能够使用返回的新版本的DataObject服务器:

 DataObject.prototype.reload = function() { var args = Array.prototype.slice.call(arguments) // extracts all arguments var client = helpers.client.validate(args) // ensures 'client' was passed in the args array before continuing args.unshift(this) // prepends 'this' (the DataObject instance) // How can I update 'this' with the response contained in the // callback passed (the last element in 'args')? return client.GET.apply(client, args) } 

用法如下所示:

 client.GET(idOrDataObject, function(err, customResponse) { var o = customResponse.dataObject // assume something changed on the server o.reload(function(err, done) { // o has now been updated with the latest copy from the server }) }) 

更新:

开始思考这将工作的唯一方法是,如果我劫持进一步下游链,例如在client.GET

 var DataObject = require('../lib/dataObject') var request = require('request') var _ = require('lodash') var GET = function(client, args) { var options = { client: client } // if a preformatted options argument passed, assign it to options if (_.isObject(args[0]) && !_.isFunction(args[0]) && args.length <= 2) { _.assign(options, args[0]) } options.callback = helpers.cb(_.last(args.filter(_.isFunction))) options.type = _.first([options.type, args[0]._type, args[0]].filter(_.isString)) options.dataObject = _.first([options.dataObject, args[0]].filter(function(property) { return (property instanceof DataObject) })) request('http://...', { body: options.body, json: true, method: 'GET' }, function(error, response) { var customResponse = new CustomResponse(response) if (options.dataObject instanceof DataObject) { options.dataObject = customResponse.dataObject // here I see both 'options.dataObject' and 'customResponse.dataObject' have the correct value for reloadTest console.log('updated', options.dataObject.reloadTest, customResponse.dataObject.reloadTest) } options.callback(error, customResponse, customResponse.dataObject) }) } 

但是即使这样做, dataObject的原始拷贝也没有被更新 – 就像它被克隆或复制一样,而不是指向原始的指针?

这是一个certificate失败的testing。 我怎样才能确保正确的指针dataObject被传递?

 var now = Date.now() client.GET('test', function(err, getResponse) { var dataObject = new DataObject(getResponse.dataObject) getResponse.dataObject.reloadTest = now // 1452109996140 console.log('now', now, 'getResponse.dataObject.reloadTest', getResponse.dataObject.reloadTest) // now 1452109996140 getResponse.dataObject.reloadTest 1452109996140 client.PUT(getResponse.dataObject, function(err, putResponse) { // updated 1452109996140 1452109996140 console.log('putResponse.dataObject.reloadTest', putResponse.dataObject.reloadTest) // putResponse.dataObject.reloadTest 1452109996140 dataObject.reload(function(err, response) { // updated 1452109996140 1452109996140 console.log('done', dataObject.reloadTest, 'response.dataObject.reloadTest', response.dataObject.reloadTest) // done 1452109916111 response.dataobject.reloadTest 1452109996140 }) }) }) 

简短的回答是,你不能。 您不能实际交换另一个对象的对象。 一些选项:

  • 使用包装器对象,并给出reload方法:

     client.GET(idOrDataObject, function(err, customResponse) { var o = new DataWrapper(customResponse); o.dataObject; // old data // assume something changed on the server o.reload(function(err, done) { o.dataObject; // new data }); }); 
  • 更新dataObject的数据,保持与之前相同的对象:

     DataObject.prototype.reload = function(callback) { client.GET(this, function(err, customResponse) { // Assign all properties from the response to the existing obj // Could also use $.extend, _.extend, etc Object.assign(this, customResponse.dataObject); callback(this); }.bind(this)); } 
  • 只需在callback中传递新对象,并忽略旧对象:

     DataObject.prototype.reload = function(callback) { client.GET(this, function(err, customResponse) { callback(customResponse.dataObject); }); }