JS对象模型肯定有不明白的地方。
来自这些资源:
我收集了我认为或认为是对象模型的准确心理表征。在这里:
所有对象都有一个属性,文档将其称为[[Prototype]]
。 [[Prototype]]
可以被认为是对对象父对象的引用。更准确地说:
The reference to the [parent's] prototype object is copied to the internal
[[Prototype]]
property of the new instance. (source 1)
您可以使用 Object.getPrototypeOf(child)
访问子项的 [[Prototype]]
属性。此处返回的值将是对父项的引用原型(prototype)(不是它的内部 [[Prototype]]
属性,而是它的实际原型(prototype))
obj.prototype
不同于对象的内部 [[Prototype]]
属性。它就像用于创建此对象实例的蓝图,而其 [[Prototype]]
属性指向用于创建其父对象实例的蓝图。
Parent.prototype === Object.getPrototypeOf(child);//真
详细说明:
如果您向
child.prototype
添加一个函数,该函数将可用于child
及其任何子级。如果给
parent.prototype
加一个函数,相当于给Object.getPrototypeOf(child)
加一个函数,那么这个函数就是可供parent
及其所有子级使用,其中包括child
及其所有siblings
。
您可以使用 Object.create()
使用您想要的任何 [[Protoype]]
属性创建一个新对象。所以你可以用它作为实现继承的一种方式。参见 source 2举个例子。
考虑到这一点,我想获得一个我自己的工作示例。我的计划是创建一个父“类”,然后创建一个继承自它的子“类”。
我想让子类实现一个方法,该方法重载了父类的一个方法。需要注意的是,我希望子版本的方法调用父版本的方法,然后做一些额外的事情。
这是我想出的,请参阅下面的相关问题:
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();
情况似乎是,当我尝试重载 Parent.myF()
时,在重载它的同时,我实际上同时修改了原始函数。这似乎是因为记录的结果是:
'derp'
'did I derp??'
'did I derp??'
大概 'did I derp??'
的第一次出现来自父函数的修改版本,我不有意这样做,然后第二个版本来自 child 的功能。
谁能详细说明为什么会这样?
最佳答案
好问题,需要一些测试和研究才能找到答案。
识别异常行为
我稍微更改了您的代码以找出在以下情况下调用了哪个函数:
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();
您可以查看 JSFiddle 并亲自尝试:http://jsfiddle.net/Lpxq78bs/
代码中的关键行是:
Child.prototype.myF = function() {
Object.getPrototypeOf(this).myF(); // this one
console.log("did I derp??");
};
在做了 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??"
解释输出
因为我在 Child
中添加了一个“名称”属性构造函数,它只会在我查看 Child
的实例时出现, 不在其 .prototype
.
所以输出的第一行表示当前this
上下文确实是 childInstance
. 但第二个既不是childInstance
,也不是 Parent.prototype
:
调用(
myF
的childInstance
):this
指的是childInstance
.Object.getPrototypeOf(this).myF();
然后寻找[[Prototype]]
的childInstance
, 这是Child.prototype
, 而不是Parent.prototype
强>。 输出:“我有错吗??”调用(
myF
的Child.prototype
):this
指的是Child.prototype
,这是childInstances
[[原型(prototype)]] 属性。所以第二次调用Object.getPrototypeOf(this).myF();
最后返回Parent.prototype
(有点)。输出:“我有错吗??”调用(由
myF
创建的Parent.prototype
实例的Object.create
):最后,myF
在 parent 身上被称为。输出:'derp'
由于您的 console.log("did I derp??")
在 myF
之后函数调用,输出顺序相反。下图说明了代码是如何遍历的:
所以你的假设是什么Object.getPrototypeOf(this).myF();
指的是错的。
ES5 中的解决方案
来自@LukeP: https://jsfiddle.net/Lpxq78bs/28/
ES6 中的替代解决方案
为了避免这种混淆,并且由于您使用的是经典继承模式,您可以查看 ES6 Classes .以下是您正在尝试做的事情的粗略示例:
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();
我希望这有助于理解发生了什么。
关于javascript - JS 继承 : calling the parent's function from within the child's function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30401967/