Javascript 对象引用

Javascript object references

我正在尝试使用一个函数为 Canvas 中的对象制作动画,所以我写了这个对象 - 我正在尝试为它制作动画:

var chartElements = {
    'bottomLine': {
        'width': 0,
        setWidth: function (x) {
            this.width = x;
        },
        getWidth: function () {
            return this.width;
        },
    },
};

...并创建它:var cE = Object.create(chartElements); 所以我的第一个想法是,只用 cE.chartElements.bottomLine.width = 10 更改 var,但这没有用,所以我写了一个函数,我可以在其中引用 getter 和 setter:

function changeIt(val, getter, setter) {
    console.log(getter());
    setter(val);
    console.log(getter());
}

现在变得非常非常奇怪,因为首先,getter-Function 返回一个 undefined,但在设置之后,它总是返回新变量,但不改变实际的 [= cE-对象的 28=]。所以看起来我正在某处创建一个新对象。

所以,怎么了,为什么我不能更改 cE 的实际 属性?

这里有两个问题。第一个问题是您试图在不存在的对象 (chartElements) 上使用 属性。而不是

cE.chartElements.bottomLine.width = 10

会是

cE.bottomLine.width = 10;

或者,当然,使用您创建的 setter:

cE.bottomLine.setWidth(10);

但是,这给我们带来了第二个问题:

通过

var cE = Object.create(chartElements);

...您正在创建一个对象,由 cE 引用,它使用 chartElements 作为其底层原型。在记忆中,你会得到这样的东西 (爱我一些 ASCII 艺术):

                         +-------------+                                  
chartElements--------+-->|   (object)  |                                  
                     |   +-------------+      +----------+               
                     |   | bottomLine  |----->| (object) |               
                     |   +-------------+      +----------+               
                     |                        | width: 0 |               
      +-----------+  |                        | setWidth |---->(function)
cE--->| (object)  |  |                        | getWidth |---->(function)
      +-----------+  |                        +----------+               
      | __proto__ |--+
      +-----------+

也就是说cE.bottomLine指的是原型的bottomLine属性。如果您更改它,您将更改原型的 bottomLine 对象,这意味着如果您有其他对象是通过 Object.create(chartElements) 创建的,如果它们使用 bottomLine,它们会看到变化(因为他们都在使用相同的 bottomLine)。

相反,您可能有 bottomLine:

的原型
var bottomLinePrototype = {
    width: 0,
    setWidth: function (x) {
        this.width = x;
    },
    getWidth: function () {
        return this.width;
    }
};

以及用于创建图表元素的构造函数或生成器函数:

这是一个构造函数:

// Constructor function
function ChartElement() {
    this.bottomLine = Object.create(bottomLinePrototype);
}

// use it via `new`
var cE = new ChartElement();

这是一个构建函数:

// Builder function
function buildChartElement() {
    return {
        bottomLine: Object.create(bottomLinePrototype)
    };
}

// Use it *without* `new`
var cE = buildChartElement();

现在,您的对象有自己的 bottomLine 对象:

      +-------------+      
cE--->|   (object)  |      
      +-------------+      +-----------+
      | bottomLine  |----->| (object)  |
      +-------------+      +-----------+     +----------+               
                           | __proto__ |---->| (object) |               
                           +-----------+     +----------+               
                                             | width: 0 |               
                                             | setWidth |---->(function)
                                             | getWidth |---->(function)
                                             +----------+               

最初看起来很相似,但不同之处在于,由于该对象有自己的 bottomLine 对象,您可以安全地使用:

cE.bottomLine.width = 10;

cE.bottomLine.setWidth(10);

...设置该实例的 bottomLinewidth,这将在它的原型上隐藏那个,给我们:

      +-------------+      
cE--->|   (object)  |      
      +-------------+      +-----------+
      | bottomLine  |----->| (object)  |
      +-------------+      +-----------+     +----------+               
                           | __proto__ |---->| (object) |               
                           | width: 10 |     +----------+               
                           +-----------+     | width: 0 |               
                                             | setWidth |---->(function)
                                             | getWidth |---->(function)
                                             +----------+               

这是可行的,因为当您执行 setget 操作时,原型属性的工作方式不同:

  • 当你得到时,如果对象本身没有属性,JavaScript引擎会寻找对象的原型,看看它是否有 属性。如果是,它使用原型的 属性 的值。如果没有,它会查找原型的原型,依此类推。

  • 当您设置时,它会在对象本身上设置值,必要时在对象上创建一个新的属性或者更新 属性 的值(如果它已经存在)。原型的属性不受影响。