简体   繁体   English

在javascript超级调用中变异了“ this”,该如何处理?

[英]mutated 'this' in javascript super call, how to deal with?

Sorry if it's hard to explain. 不好意思,不好意思。 Suppose class Y extends class Z, and class X extends class Y 假设类Y扩展了类Z,而类X扩展了类Y

The thing is if a class doesn't have a method, it calls it's super class, so far so good. 问题是,如果一个类没有方法,就称它为超类,到目前为止一切都很好。

X.prototype.v = function{return this.getV();} //getV() doesn't exist in class X

since class X extends class Y and getV() exist in class Y, the call goes here: 由于类X扩展了类Y,并且getV()存在于类Y中,因此调用转到此处:

Y.prototype.getV = function{return this.parent().getV()+1} 

the working function parent() returns an instance of it's super class. 工作函数parent()返回其超类的实例。 Suppose z also has a method getV, which returns a real int value. 假设z还具有方法getV,该方法返回实际的int值。

Z.prototype.getV = function{return 1}

So the function getV() in class Y is mean to return the getV value from Z plus 1, and send it to the lowest class X. 因此,类Y中的函数getV()的意思是从Z加1返回getV值,并将其发送到最低的类X。

Most wired part is here. 大多数有线部分在这里。 As long as the method getV is called from Xv(), 'this' in y.getV() refer to X, not Y! 只要从Xv()调用了getV方法,y.getV()中的“ this”就指向X,而不是Y!

so the function getV() in Y becomes X.parent().getV()+1, and I get 'maximum call stack size exceeded' 因此Y中的功能getV()变为X.parent()。getV()+ 1,我得到“超出最大调用堆栈大小”

A stupid but extremely effective way to solve this, is to write 解决这个问题的愚蠢但极其有效的方法是编写

this.parent().parent().getV()+1

double parents make the sender Z not y, then it returns 2 when calling X.getV() 双亲使发送方Z不是y,则在调用X.getV()时返回2

It's stupid because if the caller is Y itself, like Y.getV(), I think then 'this' correctly means Y here, then there're too many parent() calls, leading it to undefined. 这很愚蠢,因为如果调用者是Y本身,例如Y.getV(),那么我认为“ this”在这里正确地表示Y,那么parent()调用过多,导致未定义。

Some thoughts like we can get rid of 'this', and use another way to get current class. 像我们这样的想法可以摆脱'this',并使用另一种方式来获取当前类。 Less desirable way might be keeping track of all functions for all classes, and set the correct number of parent(). 不太理想的方式可能是跟踪所有类的所有函数,并设置正确的parent()数。 I believe there's more. 我相信还有更多。 However, none of them was tested out yet. 但是,它们都没有经过测试。

A minimal code example, taken from the pieces of code above, can be: 从上面的代码段中提取的最小代码示例可以是:

class Z{

}
class Y extends Z{

}
class X extends Y{

}

X.prototype.v = function{
    return this.getV();
}

Y.prototype.getV = function{
    return this.parent().getV()+1;
}

Z.prototype.getV = function{
    return 1;
}

var x = new X();
console.log(x.v());

If you use ES6 class syntax, you should use super : 如果使用ES6类语法,则应使用super

class Z {
  getV() {
    return 1;
  }
}
class Y extends Z {
  getV() {
    return super.getV() + 1;
  }
}
class X extends Y {
  v() {
    return super.getV(); // or this.getV();
  }
}
new Z().getV(); // 1
new Y().getV(); // 2
new X().getV(); // 2
new X().v();    // 2

In ES5, I would use something like 在ES5中,我会使用类似

function extend(f1, f2) {
  f1.prototype = Object.create(f2.prototype);
  f1.prototype.constructor = f1;
  f1.super = f2.prototype;
}
function Z(){}
Z.prototype.getV = function() {
  return 1;
};
function Y(){}
extend(Y, Z);
Y.prototype.getV = function() {
  return Y.super.getV.call(this) + 1;
};
function X(){}
extend(X, Y);
X.prototype.v = Y.prototype.getV;
new Z().getV(); // 1
new Y().getV(); // 2
new X().getV(); // 2
new X().v();    // 2

this refers to the context in which a function is called, or in more practical terms: it refers to the object that appears before the dot in the call. this是指在其中调用函数的上下文,或更具体地讲是这样:它是指在调用中点之前出现的对象。 When you call abc.def() , then this in def will be the same as abc . 当您调用abc.def()def this将与abc相同。

So the easiest might be to change this: 因此,最简单的方法可能是更改此设置:

X.prototype.v = function{return this.getV();}

to: 至:

X.prototype.v = function{return this.parent().getV();}

This makes the this for Y to be the above this.parent() . 这使得Y的this高于this.parent() This way you don't have to change your original call. 这样,您不必更改原始呼叫。

But if you want to keep the flexibility to define X.prototype.getV , then it is probably better to define it immediately, and instead of the above change, do this: 但是,如果您想保留定义X.prototype.getV的灵活性,那么最好立即定义它,而不是进行上述更改,请执行以下操作:

X.prototype.v = function{return this.getV();}
X.prototype.getV = function{return this.parent().getV();}

Alternative: Use apply/call 备选:使用申请/致电

You could pass an explicit reference to what the target function should use as this , using the apply method (or call which is anther flavour of the same): 你可以传递一个明确提到什么目标函数应该用this ,采用apply法(或call这是相同的花药味):

X.prototype.v = function{return this.getV.apply(this.parent(), arguments);}

Test if prototype has defined own method: 测试原型是否定义了自己的方法:

You could use hasOwnProperty : 您可以使用hasOwnProperty

X.prototype.v = function{
    var nextThis = X.prototype.hasOwnProperty('getV') ? this : this.parent();
    return this.getV.apply(nextThis, arguments);
}

` `

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM