草庐IT

JavaScript 属性继承

coder 2024-05-11 原文

我正在尝试拥有一个通用的“列表”类,它将具有:

  • 属性:项目 - 这将是一个“what-ever”的数组
  • 方法:Add() - 这将是抽象的并由特定的“列表”对象实现
  • 方法:Count() - 返回“项目”的数量

然后创建将从“List”继承的子类:

// Class 'List'
function List(){
    this.Items = new Array();
    this.Add = function(){ alert('please implement in object') }
}

// Class CDList - which inherits from 'List'
function CDList(){
    this.Add = function(Artist){
        this.Items.push(Artist)
    }
}
CDList.prototype = new List();
CDList.prototype.constructor = CDList;

// Create a new CDList object
var myDiscs = new CDList();
myDiscs.Add('Jackson');
myDiscs.Count()  <-- this should be 1


// Create a second CDList object
var myDiscs2 = new CDList();
myDiscs2.Add('Walt');
myDiscs2.Add('Disney');
myDiscs2.Count()  <-- this should be 2

...但这似乎为所有“CDList”实例创建了一个共享的“项目”列表。我需要以某种方式为每个“CDList”实例创建一个新的“Items”列表继承实例。

我该怎么做?

*我在此示例中使用“项目”列表作为示例。我希望能够在我的子类中为任何类型的继承属性创建一个新实例 - 不一定是 Array 对象。

最佳答案

只有一个数组,因为您只创建一个。该数组附加到“CDList”的原型(prototype),因此在所有实例之间共享。

要解决这个问题:不要将它附加到原型(prototype)上,而是附加到实例上。这只能在构建时完成:

// This is the constructor of the parent class!
function List() {
    this.Items = new Array();
}

// Add methods to the prototype, not to the instance ("this")
List.prototype.Add = function() { alert('please implement in object'); };

// Constructor of the child
function CDList() {
    List.call(this); // <-- "super();" equivalent = call the parent constructor
}

// "extends" equivalent = Set up the prototype chain
// Create a new, temporary function that has no other purpose than to create a
// new object which can be used as the prototype for "CDList". You don't want to
// call "new List();", because List is the constructor and should be called on
// construction time only. Linking the prototypes directly does not work either,
// since this would mean that overwriting a method in a child overwrites the
// method in the parents prototype = in all child classes.
var ctor = function() {};
ctor.prototype = List.prototype;
CDList.prototype = new ctor();
CDList.prototype.constructor = CDList;

// Overwrite actions
CDList.prototype.Add = function(Artist) {
    this.Items.push(Artist);
};

演示:http://jsfiddle.net/9xY2Y/1/


一般概念是:每个实例必须有自己的副本的东西(如本例中的“Items”数组)必须在构造时创建并附加到“this”(=实例),即做new List()new CDList()。可以跨实例共享的所有内容都可以附加到原型(prototype)上。这实质上意味着像“添加”函数这样的属性只创建一次,然后由所有实例使用(导致原始问题的原因)。

链接原型(prototype)时,不能直接链接(通常),例如:

CDList.prototype = List.prototype;
DVDList.prototype = List.prototype;

// Now add a new function to "CDList"
CDList.prototype.Foo = function() { alert('Hi'); };

由于“List”、“CDList”、“DVDList”这三个函数的原型(prototype)是直接联系在一起的,它们都指向一个原型(prototype)对象,即List.prototype。因此,如果您向 CDList.prototype 添加内容,您实际上会将其添加到 List.prototype - 这也是“DVDList”的原型(prototype)。

var dvd = new DVDList();
dvd.Foo(); // <-- alerts "hi" (oops, that wasn't intended...)

诀窍是将原型(prototype)链接到父类的新实例:

CDList.prototype = new List();

这将创建一个类型为“List()”的新对象,其特殊功能是函数“List()”的原型(prototype)链接到新对象,使您能够直接在对象上调用原型(prototype)的属性:

var l = new List();
alert( l.hasOwnProperty("Add") );  // <-- yields "false" - the object l has no
                                   // property "Add"
l.Add("foo"); // <-- works, because the prototype of "List" has a property "Add"

但是,请记住我们打算使用函数“List()”的主体在每个实例的基础上创建像这个数组“Items”这样的东西?这是您放置任何“构造函数”代码的地方,例如

function User(userId) {
    $.getJSON('/user/' + userId, ...
}

function Admin() {}
Admin.prototype = new User( // ... now what?

一个非常干净的解决方案是使用另一个函数来创建原型(prototype)对象:

var ctor = function() {}; // <-- does nothing, so its super safe
                          // to do "new ctor();"

现在可以直接链接原型(prototype),因为我们永远不会向 ctor.prototype 添加任何内容:

ctor.prototype = List.prototype;

如果我们这样做:

CDList.prototype = new ctor();

“CDList()”的原型(prototype)成为一个“ctor”类型的新对象,它没有自己的属性但可以扩展,例如通过新的“添加”功能:

CDList.prototype.Add = function() { /* CD specific code! */ };

但是,如果您不向这个新的原型(prototype)对象添加“Add”属性,“ctor()”的原型(prototype)就会启动——它是“List()”的原型(prototype)。这就是所需的行为。

此外,“List()”中的代码现在仅在您执行 new List() 或直接从另一个函数调用它时执行(在子类中通过 List .call(this);).

关于JavaScript 属性继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12027282/

有关JavaScript 属性继承的更多相关文章

  1. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

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

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

  3. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  4. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  5. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  6. 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。有没有办法覆盖用于类型

  7. ruby - Chef Ruby 遍历 .erb 模板文件中的属性 - 2

    所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP

  8. ruby - 获取数组中的值并最小化某个类属性的最优雅的方法是什么? - 2

    假设我有以下类(class):classPersondefinitialize(name,age)@name=name@age=ageenddefget_agereturn@ageendend我有一组Person对象。是否有一种简洁的、类似于Ruby的方法来获取最小(或最大)年龄的人?如何根据它对它们进行排序? 最佳答案 这样做会:people_array.min_by(&:get_age)people_array.max_by(&:get_age)people_array.sort_by(&:get_age)

  9. ruby-on-rails - 为模型创建状态属性 - 2

    我想为我的Task模型创建一个status属性,该属性将按以下顺序指示它在三部分进度中的位置:打开=>进行中=>完成。它的工作方式类似于亚马逊包裹的交付方式:已订购=>已发货=>已交付。我想知道设置此属性的最佳方法是什么。我可能是错的,但创建三个独立的bool属性似乎有点多余。实现此目标的最佳方法是什么? 最佳答案 Rails4有一个内置的enummacro.它使用单个整数列并映射到键列表。classOrderenumstatus:[:ordered,:shipped,:delivered]end状态映射如下:{ordered:0,

  10. 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发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

随机推荐