JS继承:从子函数中调用父函数

Luk*_*uke 12 javascript oop inheritance prototype

必须有一些我不了解JS对象模型的东西.

从这些资源:

我已经收集了我认为或者认为是对象模型的准确心理表示的东西.这里是:


所有对象都有一个属性,文档称之为[[Prototype]].[[Prototype]]可以被认为是对象父级的引用.更精确地:

对[parent's]原型对象的引用将复制到[[Prototype]]新实例的内部属性中.(来源1)

您可以访问[[Prototype]]子项的属性.Object.getPrototypeOf(child)此处返回的值将是父项原型的引用(不是其内部[[Prototype]]属性,而是其实际原型)

obj.prototype与对象的内部[[Prototype]]属性不同.它的作用类似于用于创建此精确对象的实例的蓝图,而其[[Prototype]]属性指向用于生成其父实例的蓝图.

  • Parent.prototype === Object.getPrototypeOf(child); //true

详细说明:

  • 如果向child.prototype函数添加函数,则可以使用该函数child及其任何子函数.

  • 如果你添加一个函数parent.prototype,相当于添加一个函数Object.getPrototypeOf(child),那么该函数将可用于parent它的所有子函数,包括它的child所有子函数siblings.

您可以使用Object.create()任何[[Protoype]]属性创建新对象.因此,您可以将其用作实现继承的方法.有关示例,请参见源2.


考虑到这一点,我希望得到一个自己的实例.我的计划是创建一个父类'class',然后创建一个继承自它的子类'class'.

我希望子类实现一个方法,该方法从父方法重载方法.需要注意的是,我希望孩子的方法版本调用父方法的版本,然后做一些额外的事情.

以下是我提出的问题,请参阅下面的相关问题:

var Parent = function() {};

Parent.prototype.myF = function() {
  console.log('derp');
};


function Child() {
  Parent.call(this);
};

//make [[prototype]] of Child be a ref to Parent.prototype
Child.prototype = Object.create(Parent.prototype);

//need to explicitly set the constructor
Child.prototype.constructor = Child;

Child.prototype.myF = function() {
  Object.getPrototypeOf(this).myF();
  console.log("did I derp??");
};

childInstance = new Child();
childInstance.myF();
Run Code Online (Sandbox Code Playgroud)

似乎是当我尝试重载时Parent.myF(),当我重载它时,我实际上是在同时修改原始函数.这似乎是这种情况,因为记录的结果是:

'derp'
'did I derp??'
'did I derp??'
Run Code Online (Sandbox Code Playgroud)

据推测,第一次出现'did I derp??'是来自父母的功能的修改版本,我不是故意要做的,那么第二个版本来自孩子的功能.

任何人都可以详细说明为什么会这样吗?

nil*_*ils 6

很好的问题,需要进行一些测试和研究才能找到它.

识别奇怪的行为

我稍微改变了你的代码,以找出在下列时调用的函数:

var Parent = function() {};

Parent.prototype.myF = function() {
  console.log('derp');
};


function Child() {
  Parent.call(this);
  this.name = 'Test'; // this is a new test property
};

//make [[prototype]] of Child be a ref to Parent.prototype
Child.prototype = Object.create(Parent.prototype);

//need to explicitly set the constructor
Child.prototype.constructor = Child;

Child.prototype.myF = function() {
  console.log(this); // here I want to find out the context, because you use it in the next line
  Object.getPrototypeOf(this).myF();
  console.log("did I derp??");
};

childInstance = new Child();
childInstance.myF();
Run Code Online (Sandbox Code Playgroud)

您可以查看JSFiddle并亲自尝试:http://jsfiddle.net/Lpxq78bs/

代码中的关键行是:

Child.prototype.myF = function() {
  Object.getPrototypeOf(this).myF(); // this one
  console.log("did I derp??");
};
Run Code Online (Sandbox Code Playgroud)

在做了一个console.log(this);找出this引用的内容之后,我看到它在第一个和第二个输出之间发生了变化did I derp??.

我得到以下输出:

Object { name: "Test" }
Object { constructor: Child(), myF: window.onload/Child.prototype.myF() }
"derp"
"did I derp??"
"did I derp??"
Run Code Online (Sandbox Code Playgroud)

解释输出

因为我在Child构造函数中添加了一个'name'属性,所以只有当我查看一个实例而Child不是它的实例时它才会出现.prototype.

所以输出的第一行意味着当前的this上下文确实是childInstance.但第二个既不是childInstance,也不是Parent.prototype:

  1. Call(myFof childInstance):this指的是childInstance.Object.getPrototypeOf(this).myF();然后寻找[[Prototype]]childInstance,这是Child.prototype,而不是Parent.prototype.输出:'我有没有解释?'
  2. Call (myFof Child.prototype):this指的Child.prototypechildInstances[[Prototype]]属性.所以第二次调用Object.getPrototypeOf(this).myF();最终返回Parent.prototype(有点).输出:'我有没有解释?'

  3. 调用(myFParent.prototype实例创建Object.create):最后,myF调用父元素.输出:'derp'

由于您console.log("did I derp??")myF函数调用之后,输出的顺序相反.下图说明了如何遍历代码:

在此输入图像描述

因此,您对Object.getPrototypeOf(this).myF();所指的内容的假设是错误的.

ES5中的解决方案

通过@LukeP:https://jsfiddle.net/Lpxq78bs/28/

ES6中的替代解决方案

为了避免这种混淆,并且由于您正在使用经典的继承模式,您可以查看ES6类.以下是您要做的事情的一个粗略示例:

class Parent {
    constructor() {

    }

    myF() {
        console.log('derp');
    }
}

class Child extends Parent {
    constructor() {
        super();
    }

    myF() {
        super.myF();
        console.log("did I derp??");
    }
}

var childInstance = new Child();
childInstance.myF();
Run Code Online (Sandbox Code Playgroud)

我希望这有助于理解会发生什么.


bug*_*s94 6

您的代码按预期工作,您获得的输出是因为Object.getPrototypeOf并且可以解释

第1步:当你调用childInstance.myF();它然后它转到下面的代码,其中this引用childInstance本身

Child.prototype.myF = function() {
  Object.getPrototypeOf(this).myF();
  console.log("did I derp??");
};
Run Code Online (Sandbox Code Playgroud)

然后Object.getPrototypeOf返回childInstance.[[Prototype]]哪个是Child.prototype再次调用myF方法(在执行方法后留下第二行打印)但下次this将引用childInstance.[[Prototype]].

第2步:在此调用this指向childInstance.[[Prototype]](或Child.prototype对象本身)

Child.prototype.myF = function() {
  Object.getPrototypeOf(this).myF();
  console.log("did I derp??");
};
Run Code Online (Sandbox Code Playgroud)

现在Object.getPrototypeOf返回childInstance.[[Prototype]].[[Prototype]](这是Child.prototype.[[Prototype]]),它Parent.prototype再次调用myF方法,但这次myF方法将打印derp,因为Parent.prototype正在调用myF方法.在那之后,第二行将打印我derp.

步骤3:然后该功能返回到步骤1以执行第二行,再次打印我的derp