如何在基础对象上声明数据结构,使它们在每个扩展对象中保持独立?

How to declare data structures on base objects, so they remain independent in each extended object?

示例:

var Person = {
   name : '',
   collection  : new Array(),
   addToCollection : function(x)
   {
     this.collection.push(x);
   },
   printCollection: function() {
       console.log(this.collection);
   }
};


var skywalker = Object.create(Person);
skywalker.name = 'Anakin Skywalker';
skywalker.addToCollection(1);
skywalker.printCollection();   // prinnts [1]


var skywalker2 = Object.create(Person);
skywalker2.name = 'Anakin Skywalker 2';
skywalker.addToCollection(2);
skywalker2.printCollection();   // prints [1, 2]

我想实现 skywalker2.printCollection();打印 [2]。我希望基础对象 Person 关注集合,并公开 addToCollection(x) 等操作。

你必须这样做;

var Person = {
   name : '',
   addToCollection : function(x)
   {
     this.collection.push(x);
   },
   printCollection: function() {
       console.log(this.collection);
   }
};
var sw1 = Object.create(Person),
    sw2 = Object.create(Person);

sw1.collection = new Array();
sw2.collection = new Array();
sw1.addToCollection(1);
sw2.addToCollection(2);

sw1.printCollection(); // <- 1
sw2.printCollection(); // <- 2

好吧,根据 OP 的评论,提供了一些关于在 JS 中创建对象的信息。 Object.create() 将允许您定义一个对象的原型,并且原型中的任何内容都在实例化对象之间共享。所以在这种情况下,集合数组是共享的。如果您不希望 collection 被共享,您只需在实例化对象中创建它,如我在前面的代码片段中所示。但是据我了解,您不希望那样。好的,还有另一种方法可以实现这一目标。我们可以将 collection 数组作为私有 属性 函数下的数组,并通过我们的原型方法通过闭包访问它。然后我们将实现我们想要的。就这样;

function collectionInClosure(){
  var collection = [],
   getCollection = function(){return collection},
   setCollection = function(v) {collection.push(v)};
  return {
           printCollection: function() {console.log(getCollection())},
           addToCollection: setCollection
         };
}

var sw1 = Object.create(collectionInClosure());
    sw2 = Object.create(collectionInClosure());

sw1.addToCollection(1);
sw2.addToCollection(2);

sw1.printCollection(); // <- 1
sw2.printCollection(); // <- 2

这是非常普遍的做法,能够在基础 classes 中抽象一些属性是一个很大的便利,这样我们在实例化或扩展对象时就不需要关心它们了。 class 像 Java 这样的其他 class 面向对象的语言为我们做到了这一点,它通常被认为是开发人员理解的更直观的行为。

可以通过两种方式解决此特定问题:

1) 使用 ES6

class Animal { 
  constructor(name) {
    this.name = name;
    this.collection = [];
  }
  addToCollection(x) {
    this.collection.push(x);
  }
  printCollection() {
    console.log(this.collection);
  }
}

var dog = new Animal();
dog.addToCollection(1);
dog.printCollection();    // prints 1

var dog2 = new Animal();
dog2.addToCollection(2);
dog2.printCollection();   // prints 2

由于并非所有浏览器都支持 ES6(大多数浏览器默认关闭 ES6),请使用 Babel 或类似的 polyfill 才能使用上述语法。

Babel 将使用 ES5 来模拟 ES6 语法,javascript 类似于:

"use strict";

var _createClass = function() {
  function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  return function(Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps);
    if (staticProps) defineProperties(Constructor, staticProps);
    return Constructor;
  };
}();

var Animal = function() {
  function Animal(name) {
    // ..  some Babel Class checks here

    this.name = name;
    this.collection = [];
  }

  _createClass(Animal, [{
    key: "addToCollection",
    value: function addToCollection(x) {
      this.collection.push(x);
    }
  }, {
    key: "printCollection",
    value: function printCollection() {
      console.log(this.collection);
    }
  }]);

  return Animal;
}();

var dog = new Animal();
dog.addToCollection(1);
dog.printCollection();  // prints 1

var dog2 = new Animal();
dog2.addToCollection(2);
dog2.printCollection();    // prints 2

2) 另一种方法是使用受 Babel 方法启发的 ES5 语法:

var Person = function() {

    function Person(name) {
        this.name = name;
        this.collection = [];  
        this.addToCollection = function (x) {
            this.collection.push(x);
        } 
        this.printCollection = function () {
           console.log(this.collection);
        }
    };
    return Person;
}();

var p1 = new Person();
p1.addToCollection(1);
p1.printCollection();    // prints 1

var p2 = new Person();
p2.addToCollection(2);
p2.printCollection();   // prints 2

通过将构造函数 Person 包装在立即执行的函数中,我们确保每次有人实例化 Person 时都会创建一个新的构造函数 class;