Javascript 原型中回调期间上下文丢失

Javascript 原型中回调期间上下文丢失,javascript,this,Javascript,This,我有一个简单的构造函数,它有firstname和lastname function Parent(){ this.firstName; this.lastName; } 该构造函数的原型中定义了四个函数,它们执行自己的任务 Parent.prototype.flipName = function () { return this.lastName + ' ' + this.firstName; } Parent.prototype.setFirstName = fun

我有一个简单的构造函数,它有firstname和lastname

function Parent(){
    this.firstName;
    this.lastName;
}
该构造函数的原型中定义了四个函数,它们执行自己的任务

Parent.prototype.flipName = function () {
    return this.lastName + ' ' + this.firstName;
}

Parent.prototype.setFirstName = function (name) {
    this.firstName = name;
}

Parent.prototype.setLastName = function (last) {
    this.lastName = last;
}

Parent.prototype.getFullName = function (callback) {
    // used alert for the sake of simplicity
    alert("Callback: " + callback());
    return this.firstName + ' ' + this.lastName;
}
为了证明这一点,我也附上了

因此,我的问题是,每当我在getFullName函数上传递callback时,这个会以某种方式丢失父对象的上下文(在我们的例子中是johny),并返回为
undefined
但是,此
getFullName
函数上运行良好

我知道
这个
指向的是
窗口
对象,而不是回调中的
父对象
,但我似乎找不到它背后的原因。

Parent.prototype.getFullName = function (callback) {
// used alert for the sake of simplicity
 alert("Callback: " + callback.call(this));
 return this.firstName + ' ' + this.lastName;
};
原因是当您传入函数指针johny.flipName时,它是一个匿名函数。您可以通过将其记录到控制台来查看这一点。因此,函数将在全局(
窗口
)范围内执行

要解决这个问题,必须(如果愿意)保留回调的范围。您可以使用

Parent.prototype.getFullName = function (callback) {
// used alert for the sake of simplicity
 alert("Callback: " + callback.call(this));
 return this.firstName + ' ' + this.lastName;
};

没有足够的声誉来添加评论,所以这里是另一个答案。特拉维斯对这个问题的提问方式是正确的。然而,我认为实际用例可能要复杂一些。如果你使用

callback.call(this);
将使用“this”值执行回调函数,该值引用调用getFullName的对象。当您在回调函数中时,这可能是您希望“This”所指的内容,也可能不是。以下面的例子为例

function Parent() {
    var self = this;
    self.firstName;
    self.lastName;
}

function Child() {
    var self = this;
    self.firstName;
}

Child.prototype.getName = function() {
    return this.firstName;
}

Parent.prototype.getFullName = function (callback) {
    // used alert for the sake of simplicity
    alert("Callback: " + callback.call(this));
    return this.firstName + ' ' + this.lastName;
}
Parent.prototype.flipName = function () {
    return this.lastName + ' ' + this.firstName;
}
Parent.prototype.setFirstName = function (name) {
    this.firstName = name;
}

Parent.prototype.setLastName = function (last) {
    this.lastName = last;
}

var johny = new Parent();
johny.setFirstName("Johny");
johny.setLastName("Bravo");

var sue = new Parent();
sue.setFirstName("Sue");
sue.setLastName("Bravo");

// used alert for the sake of simplicity
alert("FullName: " + johny.getFullName(sue.flipName));
当您执行callback.call(this)时;当你可能期待着“布拉沃·苏”的时候,你实际上会得到“布拉沃·约翰尼”

我不知道这是否是最佳实践,但我会做的是:

alert("FullName: " + johny.getFullName(function() {
    return sue.flipName();
}));
在全局代码中,它始终引用全局对象。在函数代码中,该值由函数的调用方式设置(例如,直接调用,作为一种方法,使用new、call、apply或bind)

如果希望回调中的该值具有特定值,则在调用中使用或设置它,例如


如果未设置此值,它将默认为全局对象(浏览器中的窗口),或者在严格模式下,它将是未定义的。

请参阅不确定发生此情况的原因,但如果替换警报(“回调:“+Callback()”);带有警报(“回调:+Callback.apply(this));“我知道这是指向回调中的窗口对象,而不是父对象,但我似乎找不到它背后的原因。”因为如果以“正常方式”调用函数,即
func()
,则
引用全局对象(或
在严格模式下未定义的
)。有关更多信息,请参阅。这不是“上下文”,而是由调用函数的方式或使用设置的属性。如果不传递,通常应使用
call
,而不是
apply
arguments@megawac-为什么?没有比这更简单的理由了,更快的操作速度,在内存中减少一个字节的成本typing@megawac-我将给出1字节。更快?我的测试没有结果(但似乎倾向于打电话)。请参阅我的编辑。OP的问题与“匿名”函数(即函数表达式)或作用域无关。函数的作用域完全由调用函数的方式或使用绑定来设置。这与作用域无关。它本质上是一个局部变量,在非严格模式下引用对象,或在严格模式下引用任何值。