【问题标题】:What's the best way to modify an inherited array in javascript without changing its parent在不更改其父级的情况下修改javascript中继承数组的最佳方法是什么
【发布时间】:2020-02-20 18:09:37
【问题描述】:

我想创建一个继承自其他对象的对象。在构造后代时,我想在不更改父对象的情况下将一些项目推送到继承的数组中。

假设我有一个叫做篮子的对象:

function Basket(){
}

然后我像这样填充它:

Basket.prototype {
    “price”: 5,
    “contents” : [“apple”, “orange”, “grape”]
}

现在我想扩展它。我想添加一些属性并更改一些。我这样做了:

function BigBasket(){
    this.price = 6; // change a property. This goes well, when an instance is created, price is still 5 in prototype and also in instances of Basket and it is 6 in the instance that is created from this descendant.
    this.greetingcard = “Congratulations” // add a property. Goes well

现在我想在内容属性中添加一个项目,但只在后代实例中。

这是错误的:

    this.contents.push(“banana”); 

似乎 this.contents 包含对原型数组的引用,因此当将香蕉推送到它时,意味着 Bigbasket 和 Basket 的实例也会在其内容中获取香蕉。因此,我首先复制了 Basket.contents(父内容),如下所示:

    this.contents = Object.getPrototypeOf(this).contents.slice(); // seems __proto__ is deprecated, so using getPrototypeOf here and then pushed the banana:
    this.contents.push(‘banana’);
}

这似乎有效,但这是正确的方法吗?我知道数组也是一个对象,所以我尝试了这个:

    this.contents = Object.create(Basket.prototype.contents);
    this.contents.push('banana');

这也有效,似乎是一种更通用的方式。此外,在 Chrome 中,最后推送的项目只是后代的属性,而其余的数组项目是原型的属性。对我来说似乎很优雅。

不过,这对我来说看起来有点笨拙。我做错了吗?试图找出但在扩展对象中找不到关于数组主题的任何内容。有没有办法在实例化时复制所有属性而不是引用的后代?

谢谢!

【问题讨论】:

  • 一个技巧开始。原型中永远不会有对象。原型最适合不太可能改变的静态值。
  • 当你访问this.contents时,它会直接在对象上查找属性。没有找到。然后,它将在其[[Prototype]] 中查找该属性。这里是Basket.prototype.contents。因此,它将推送到该数组。在第二种情况下,有一个 own contents 属性,因此它永远不会在 [[Prototype]] 中查找

标签: javascript arrays object inheritance properties


【解决方案1】:

你可以试试这样的:

  • 不要将pricecontent 放在原型上,而是将它们作为Basket 的属性。
  • 继承BigBasket并将其原型设置为Basket的实例。这将使您能够访问 Basket 的属性。
  • BigBasket 中定义一个私有变量content,其工作是维护孩子的内容。
  • 添加一个setter函数来改变这个变量

    • addContent:为孩子的内容添加新值
    • removeContentByIndex:根据索引删除值。
    • getContent:这将返回content 的副本以消除副作用。这也将允许您对内容进行自定义定义。在这种情况下,它自己的内容+父母的内容

    这将允许您定义一个 API 以与内容进行通信,还允许您创建一个公开的限制数据。暴露一切可能会导致问题。暴露需要的东西总是更好。

注意:原型上有对象可能会导致问题,因为对象会产生副作用。您应该只使用 Parent 的值作为默认值。

function Basket() {
  this.price = 5;
  this.contents = ["apple", "orange", "grape"]
}

function BigBasket() {
	const content = [];
  this.price = 6;
  this.greetingcard = "Congratulations";
	this.addContent = function(value) {
  	content.push(value);
  }
  this.removeContentByIndex = function(index) {
  	content.splice(index, 1);
  }
  this.getContents = function() {
  	return [].concat(this.__proto__.contents, content);
  }
}

BigBasket.prototype = new Basket();

const bb1 = new BigBasket();
const bb2 = new BigBasket();
bb1.addContent('banana');
console.log(bb1.getContents(), bb2.getContents())

【讨论】:

  • 注意:如果您认为此答案有任何遗漏或任何不正确的信息,请在您的投票中分享您的观点。
猜你喜欢
  • 1970-01-01
  • 2021-06-15
  • 2022-11-12
  • 2018-06-01
  • 2013-09-13
  • 1970-01-01
  • 2020-08-22
  • 2011-01-04
  • 1970-01-01
相关资源
最近更新 更多