javascript - 返回使用 .apply() 调用的函数时从回调中更新 'this'

标签 javascript node.js

我有一个 ProjectClient 类,其中包含一个用于进行 HTTP 调用的方法 (.GET())。它以与 相同的方式支持一些参数和回调。 ,但在幕后也有一些复杂的 url 和 header 构建函数:

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

在成功响应时,返回的对象类型之一是 DataObject:

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

我正在向 DataObject 类添加一个名为 reload() 的便捷方法,它会回调 client.GET() 方法并重新加载自身,但我希望能够使用从服务器返回的新版本的 DataObject 更新 this:

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 的原始副本也没有被更新——就好像它被克隆或复制了,而不是指向原始副本的指针?

这是一个证明失败的测试。如何确保传递指向 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));
    }
    
  • 只需在回调中传递新对象并忽略旧对象:

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

关于javascript - 返回使用 .apply() 调用的函数时从回调中更新 'this',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34641028/

相关文章:

javascript - 针对多个属性的高效 Marionette 排序 CollectionView

javascript - 如何从 php 检索 bool 值到 javascript 文件

docker 中的 node.js - 无法找到绑定(bind)文件 .../bcrypt_lib.node

jquery - Rails 5 - 当前 ExecJS 运行时不支持 ES6。请安装最新的 Node.js

node.js - NodeJS HTTP - 从要代理的请求中删除 header

javascript - 使用 Angular 过滤器但不使用 jQuery 删除 DOM 元素

javascript - 添加 react 原生矢量图标以 react 原生与 react 原生网络时出错

javascript - 无法从 Firebase 下载数据 - TypeError : undefined is not an object

windows - Npm 请以 root/管理员身份再次尝试使用此命令

node.js - 如何使用Youtube API获得通过videoCategoryId过滤的喜欢的视频