Javascript和回调

时间:2016-02-03 16:07:23

标签: javascript callback

我写了一个JavaScript函数,它运行得很好,但它很长,所以我想把它分解成更小的函数。我认为这很容易(也许是这样)但是我遇到了问题!

所以我的代码结构如下:

getPosition: function(a) {
    if (true) {
        position = this.getPoint(a); 
    }
}, 
getPoint: function(a) {
    var position; 
    var options = a.target.parentElement.children; 
    [].forEach.call(options, function(option){
        if (option.type == "point") {
            position = this.getNewPoint(a, option); 
        } else if (option.type == "line") { 
            position = this.getNewLine(a, option); 
        }
    }
    return position; 
}, 
getNewPoint: function(a, option){
    ...
    return point; 
}, 
getNewLine: function(a, option){
    ...
    return line; 
}

尝试此操作时,我发现错误this.getNewPointthis.getNewLine未定义。这有意义,因为范围,所以我决定尝试使用回调:

getPosition: function(a) {
    if (true) {
        position = this.getPoint(a, this.getNewPoint, this.getNewLine); 
    }
}, 
getPoint: function(a, pointCallback, lineCallback) {
    var position; 
    var options = a.target.parentElement.children; 
    [].forEach.call(options, function(option){
        if (option.type == "point") {
            position = pointCallback(a, option); 
        } else if (option.type == "line") { 
            position = lineCallback(a, option); 
        }
    }
    return position;
}, 
getNewPoint: function(a, option){
    ...
    return point; 
}, 
getNewLine: function(a, option){
    ...
    return line; 
}

这个get是要调用的函数,但是,(我猜是这样的)因为Javascript的异步性质,代码在没有回调完成的情况下继续,所以永远不会返回返回值。看起来当我输入一些console.log()进行测试时,它开始工作了。我猜这是因为它迫使代码放慢速度。有什么想法吗?

更新: 由于我收到的非常棒的帮助,我已经让它工作到了一定程度。因此,只要永远不会调用getNewLine函数,它就可以正常工作。所以我认为我的getNewLine函数返回的方式有问题,因为它打破了一切!所以这是关于该功能的更多细节:

getNewLine: function(a, option){
    var line; 
    var endPoints = option.points; 
    for (var i = 0; i < (endPoints.length - 1); i++) { 
        ... math here 
        if (distance <= linePadding) { 
            if (true) {
                line = option; 
                return line; //Want to break the loop and for the function to return 
            }
        } 
    } 
    return line; 
}

3 个答案:

答案 0 :(得分:2)

你没有介绍任何真正异步的东西,只是一种应用函数的不同方法。与使用回调相比,您的问题更容易解决;保存对正确的this

的引用
getPoint: function(a) {
    var self = this; // <--
    var options = a.target.parentElement.children; 
    [].forEach.call(options, function(option){
        if (option.type == "point") {
            newPoint = self.getNewPoint(a, option); // <--
        } else if (option.type == "line") { 
            newLine = self.getNewLine(a, option); // <--
        }
    });
},

至于为什么你的新解决方案不起作用,看起来你没有用正确的上下文传递回调。首先,我相信你打算输入

position = this.getPoint(a, this.getNewPoint, this.getNewLine); 

但问题是你再次失去正确的this上下文。您可以通过使用.bind

明确设置来解决此问题
position = this.getPoint(a, this.getNewPoint.bind(this), this.getNewLine.bind(this));

Bind创建给定函数的副本,其中this上下文已明确设置。

我实际上写了一个答案,解释this如何确定here。正如费利克斯·克林所指出的那样,.forEach接受另一个论证来设定this的背景:

[].forEach.call(options, function(option) {
  // Your same code as before
}, this); // <-- Set the context

答案 1 :(得分:1)

这里有 no 异步代码。仅仅因为你将函数作为参数传递并不意味着它是异步的。

您遇到的问题是getPoint没有返回任何内容!您需要return语句才能返回任何内容。

对于第一个示例,每次输入新this时,function(){}的值都会更改。 this基于函数的调用方式。在forEach内,this&#34;数组中的元素&#34; 全局window对象,而不是您的对象。

你可以&#34;备份&#34; this变量,然后在forEach内使用。您可以通过在回调后传递this来设置forEach的值。< / p>

getPoint: function(a) {
    var options = a.target.parentElement.children,
        position;

    [].forEach.call(options, function(option){
        if (option.type == "point") {
            position = this.getNewPoint(a, option); 
        } else if (option.type == "line") { 
            position = this.getNewLine(a, option); 
        }
    }, this);

    return position;
}, 

答案 2 :(得分:-3)

您认为this正在改变范围。 this始终指向最近的父函数。因此,如果将代码分成多个函数,this变量将根据函数而变化。

解决此问题的一种方法是,当从另一个函数调用一个函数时,您可以使用this.call方法在函数中设置.apply

.callthis范围作为第一个参数,以下所有参数都是传递给被调用函数的实际参数。 (argument = parameter -1)。

.applythis范围作为第一个参数,其第二个参数是一个数组,它将作为参数传递给被调用函数。

所以在这种情况下我会建议

getPosition: function(a) {
    if (true) {
        position = this.getPoint.call(this, a); 
    }
}, 
getPoint: function(a) {
    var position; 
    var options = a.target.parentElement.children; 
    [].forEach.call(options, function(option){
        if (option.type == "point") {
            position = this.getNewPoint.call(this, a, option); 
        } else if (option.type == "line") { 
            position = this.getNewLine.call(this, a, option); 
        }
    }
    return position; 
}, 
getNewPoint: function(a, option){
    ...
    return point; 
}, 
getNewLine: function(a, option){
    ...
    return line; 
}