草庐IT

Javascript 原型(prototype)继承——后代相互覆盖

coder 2024-05-14 原文

我正在创建两个对象(继承),它们都继承自 Base。 第二个对象的属性分配覆盖第一个对象中的值。

有什么想法吗?如何进行适当的继承,以便基类将包含其继承后代的公共(public)成员,但后代可以在不相互干扰的情况下分配自己的值。

var testParams1 = { title: "john" };
var testParams2 = { title: "mike" };

Function.prototype.inheritsFrom = function (baseClass)
{
    this.prototype = new baseClass;
    this.prototype.constructor = this;
    this.prototype.base = baseClass.prototype;
    return this;
};

function Base() {
    this.viewModel = {};
    this.viewModel.title = (function ()
    {
        var savedVal = "";
        return function (newVal)
        {
            if (typeof (newVal) === "undefined")
            {
                return savedVal;
            }
            savedVal = newVal;
        };
    })();
}
function Inherits(params) {
    this.viewModel.title(params.title);
}

Inherits.inheritsFrom(Base);

///// preparing code:
var testObj1 = new Inherits(testParams1);
var testObj2 = new Inherits(testParams2);

///// testing code:
equals(testObj1.viewModel.title(), testParams1.title, "first instance ok"); // returns "john"
equals(testObj2.viewModel.title(), testParams2.title, "second instance ok");  // also returns "john"

最佳答案

问题

  • Base 类构造函数被调用一次且仅调用一次。
    this.prototype = new baseClass;
  • 特权方法将跨实例引用相同的 this 对象,因为这些方法是在构造函数中创建的(仅调用一次)。

基于个人意见的问题

  • 如果您计划使用不属于您的 JavaScript,您应该尽量避免修改 native 原型(prototype)(即 Function.prototype)。

解决方案

  • 为创建的每个新实例调用构造函数和父构造函数。
  • 继承父原型(prototype)链(不是父类的实例)。
  • 在原型(prototype)链中创建的实例数量与调用构造函数的数量保持 1:1 的比例。

Max问题的最终解

请特别注意 inherits 函数和 ParentClass.call(this, title); 行。 要查找的构造函数是 ParentClassChildClass

/**
 * 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 函数的人。

如何使用原型(prototype)链解析属性

当在实例级别找不到属性时,JavaScript 将尝试通过搜索实例构造函数原型(prototype)链来解析丢失的属性。如果在第一个原型(prototype)对象中没有找到该属性,它将搜索父原型(prototype)对象,依此类推,一直搜索到 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);
}

现在构造函数和父构造函数被正确调用。但是,只有在构造函数中定义的方法才会存在。不会使用父原型(prototype)上的属性,因为它们尚未链接到子构造函数原型(prototype)。

继承父原型(prototype):尝试 #1

// Bad
ChildConstructor.prototype = new ParentConstructor();

根据是否使用 ParentConstructor.call(this),父构造函数将只被调用一次或多次。

继承父原型(prototype)尝试 #2

// Bad
ChildConstructor.prototype = ParentConstructor.prototype;

尽管这在技术上是可行的,但对 ChildConstructor.prototype 的任何赋值也将被赋值给 ParentConstructor.prototype,因为对象是通过引用传递的,而不是通过复制传递的。

继承父原型(prototype)尝试#3

// Almost there
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();

这允许您将属性分配给 ChildConstructor.prototype,因为它是一个临时匿名函数的实例。 在 TempConstructor 的实例上找不到的属性随后将检查其属性的原型(prototype)链,因此您已成功继承父原型(prototype)。唯一的问题是 ChildConstructor.prototype.constructor 现在指向 TempConstructor

继承父原型(prototype)尝试#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);

关于Javascript 原型(prototype)继承——后代相互覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14564155/

有关Javascript 原型(prototype)继承——后代相互覆盖的更多相关文章

  1. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  2. ruby - 无法覆盖 irb 中的 to_s - 2

    我在pry中定义了一个函数:to_s,但我无法调用它。这个方法去哪里了,怎么调用?pry(main)>defto_spry(main)*'hello'pry(main)*endpry(main)>to_s=>"main"我的ruby版本是2.1.2看了一些答案和搜索后,我认为我得到了正确的答案:这个方法用在什么地方?在irb或pry中定义方法时,会转到Object.instance_methods[1]pry(main)>defto_s[1]pry(main)*'hello'[1]pry(main)*end=>:to_s[2]pry(main)>defhello[2]pry(main)

  3. ruby - 覆盖相似的方法,更短的语法 - 2

    在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a

  4. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  5. ruby-on-rails - Rails 单表继承 : How to override the value written to the type field - 2

    在我的系统中,我已经定义了STI。Dog继承自Animal,在animals表中有一个type列,其值为"Dog"。现在我想让SpecialDog继承自dog,只是为了在某些特殊情况下稍微修改一下行为。数据还是一样。我需要通过SpecialDog运行的所有查询,以返回数据库中类型为Dog的值。我的问题是因为我有一个type列,rails将WHERE"animals"."type"IN('SpecialDog')附加到我的查询中,所以我不能获取原始的Dog条目。所以我想要的是以某种方式覆盖rails在通过SpecialDog访问数据库时使用的值,使其表现得像Dog。有没有办法覆盖用于类型

  6. Ruby - 如何处理子类意外覆盖父类(super class)私有(private)字段的问题? - 2

    假设您编写了一个类Sup,我决定将其扩展为SubSup。我不仅需要了解你发布的接口(interface),还需要了解你的私有(private)字段。见证这次失败:classSupdefinitialize@privateField="fromsup"enddefgetXreturn@privateFieldendendclassSub问题是,解决这个问题的正确方法是什么?看起来子类应该能够使用它想要的任何字段而不会弄乱父类(superclass)。编辑:equivalentexampleinJava返回"fromSup",这也是它应该产生的答案。 最佳答案

  7. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  8. ruby - 解释为局部变量会覆盖方法名称吗? - 2

    如thisquestion,当在其自己的赋值中使用未定义的局部变量时,它的计算结果为nil。x=x#=>nil但是当局部变量的名称与现有的方法名称冲突时,就比较棘手了。为什么下面的最后一个示例返回nil?{}.instance_eval{a=keys}#=>[]{}.instance_eval{keys=self.keys}#=>[]{}.instance_eval{keys=keys}#=>nil 最佳答案 在Ruby中,因为可以在没有显式接收器和括号的情况下调用方法,所以在局部变量引用和无接收器无参数方法调用之间存在语法歧义:f

  9. ruby-on-rails - capybara poltergeist - 覆盖用户代理 - 2

    有人知道如何将capybarapoltergeist的用户代理覆盖到移动用户代理以进行测试吗?我发现了一些有关为seleniumwebdriver配置它的信息:http://blog.plataformatec.com.br/2011/03/configuring-user-agents-with-capybara-selenium-webdriver/这在capybara闹鬼中怎么可能? 最佳答案 请参阅poltergeistgithub页面上的链接:https://github.com/teampoltergeist/polte

  10. ruby-on-rails - 安装多个版本的 Rails 会覆盖以前的安装吗? - 2

    如果我一直输入geminstallrails使用不同版本的Rails会怎样?例如,我可以输入:geminstallrails--verson3.2.10或geminstallrails这给了我版本3.2.12。问题每次安装都会覆盖之前的吗?它会删除所有旧文件并添加我正在安装的新版本吗?或者如果我运行它两次,它会保留一些文件吗?我正在使用Ubuntu。 最佳答案 它将安装两个独立的gem。实际的可执行文件rails将调用最新版本。你可以覆盖它__例如,rails_3.2.10_将执行Rails3.2.10。bundler顺便说一下,如

随机推荐