问题)
- 类
Base
构造函数只被调用一次。
this.prototype = 新基类;
- 特权方法将
this
跨实例引用相同的对象,因为这些方法是在构造函数中创建的(仅调用一次)。
基于意见的问题
Function.prototype
如果您打算与不属于您的 JavaScript 一起工作,您应该尽量避免修改本机原型(即 . )。
解决方案
- 为创建的每个新实例调用构造函数和父构造函数。
- 继承父原型链(不是父类的实例)。
- 保持原型链中创建的实例数与调用构造函数数的比例为 1:1。
Max问题的最终解决方案
请特别注意inherits
功能和ParentClass.call(this, title);
线路。要寻找的构造函数是ParentClass
和ChildClass
/**
* Allows a child constructor to safely inherit the parent constructors prototype chain.
* @type {Function}
* @param {!Function} childConstructor
* @param {!Function} parentConstructor
*/
function inherits(childConstructor, parentConstructor){
var TempConstructor = function(){};
TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain
childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor
};
//////////////////////////////////////
/** @constructor */
function ParentClass(title) {
this.setTitle(title);
var randId_ = Math.random();
/** @return {number} */
this.getPrivlegedRandId = function()
{return randId_;};
};
/** @return {string} */
ParentClass.prototype.getTitle = function()
{return this.title_;};
/** @param {string} value */
ParentClass.prototype.setTitle = function(value)
{this.title_ = value;};
//////////////////////////////////////
/**
* @constructor
* @param {string} title
* @param {string} name
*/
ChildClass = function (name, title) {
ParentClass.call(this, title); // Call the parent class constructor with the required arguments
this.setName(name);
}
inherits(ChildClass, ParentClass); // Inherit the parent class prototype chain.
/** @return {string} */
ChildClass.prototype.getName = function()
{return this.name_;};
/** @param {string} value */
ChildClass.prototype.setName = function(value)
{this.name_ = value;};
掉进兔子洞
对于那些好奇为什么它起作用而不是简单地记住它的inherits
功能的人。
如何使用原型链解析属性
当在实例级别找不到属性时,JavaScript 将尝试通过搜索实例构造函数原型链来解决丢失的属性。如果在第一个原型对象中没有找到该属性,它将搜索父原型对象,依此类推,直到Object.prototype
. 如果在其中找不到它,Object.prototype
则会引发错误。
从子构造函数调用父构造函数:尝试 #1
// Bad
var ChildConstructor = function(arg1, arg2, arg3){
var that = new ParentConstructor(this, arg1, arg2, arg3);
that.getArg1 = function(){return arg1};
return that;
}
使用创建的任何变量都new ChildConstructor
将返回ParentConstructor
. 将ChildConstructor.prototype
不会被使用。
从子构造函数调用父构造函数:尝试 #2
// Good
var ChildConstructor = function(arg1, arg2, arg3){
ParentConstructor.call(this, arg1, arg2, arg3);
}
现在适当地调用构造函数和父构造函数。但是,只有在构造函数中定义的方法才会存在。不会使用父原型上的属性,因为它们尚未链接到子构造函数原型。
继承父原型:尝试#1
// Bad
ChildConstructor.prototype = new ParentConstructor();
父构造函数将被调用一次或多次调用,具体取决于是否ParentConstructor.call(this)
使用。
继承父原型尝试#2
// Bad
ChildConstructor.prototype = ParentConstructor.prototype;
虽然这在技术上是可行的,但任何分配ChildConstructor.prototype
也将被分配给,ParentConstructor.prototype
因为对象是通过引用而不是通过复制传递的。
继承父原型尝试#3
// Almost there
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
这允许您分配属性,ChildConstructor.prototype
因为它是临时匿名函数的实例。在 的实例上找不到的属性TempConstructor
将检查它的原型链的属性,因此您已成功继承父原型。唯一的问题是,ChildConstructor.prototype.constructor
现在指向TempConstructor
.
继承父原型尝试#4
// Good
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
ChildConstructor.prototype.constructor = ChildConstructor;
全部一起
var ParentConstructor = function(){
};
var ChildConstructor = function(){
ParentConstructor.call(this)
};
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
ChildConstructor.prototype.constructor = ChildConstructor;
您已成功从父类继承!让我们看看我们是否可以做得更好。
继承函数
function inherits(childConstructor, parentConstructor){
var TempConstructor = function(){};
TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain
childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor (currently set to TempConstructor )
};
var ParentConstructor = function(){
};
var ChildConstructor = function(){
ParentConstructor.call(this)
};
inherits(ChildConstructor, ParentConstructor);