使对象的所有属性可变

Make all properties of object mutable

我如何定义一个对象的属性,以便如果更改其中一个属性,则所有其他属性都会自动更新。

到目前为止我已经想出了这段代码,但它不起作用:

function CreateNamed(first, last) {
    Object.defineProperties(this, {
           "firstName": {
            value: first,
            writable: true
        },
            "lastName": {
            value: last,
            writable: true
        },
            "fullName": {
            value: first + ' ' + last,
            writable: true
        }
    });
}

所以在创建一个新的对象后,可以适当地改变它:

var b = new CreateNamed('Bill', 'Gates'); // Bill Gates
b.firstName = 'Paul'; // b.fullName = Paul Gates
b.lastName = 'Wood'; // b.fullname = Paul Wood
b.fullName = 'Chuck Norris' // b.firstName = Chuck, b.lastName = Norris

value 不是动态计算的。它不会随着对象的改变而改变。为了动态计算属性,您需要使用 get and set:

定义 getter 和 setter

get
A function which serves as a getter for the property, or undefined if there is no getter. The function return will be used as the value of property. Defaults to undefined.

set
A function which serves as a setter for the property, or undefined if there is no setter. The function will receive as only argument the new value being assigned to the property. Defaults to undefined.

function CreateNamed(first, last) {
    this.first = first;
    this.last = last;
    Object.defineProperties(this, {
           "firstName": {
           get: function() { return this.first; },
           set: function(name) { this.first = name; }
        },
            "lastName": {
           get: function() { return this.last; },
           set: function(name) { this.last = name; }
        },
            "fullName": {
            get: function () { return this.first + ' ' + this.last },
            set: function (name) {
              if (!name.match(/^[a-z]+ [a-z]+$/))
                throw new Error('I cannot parse that name')
              var parts = name.split(' ')
              this.first = parts[0];
              this.last = parts[1];
            }
        }
    });

}

var user = new CreateNamed('bob', 'smith');
document.write(user.fullName); // bob smith

user.firstName = "john"; 
document.write(user.fullName); // john smith

user.fullName = "tony brian";
document.write(user.firstName); // tony
document.write(user.lastName); // brian

正确。

但是有一个更简单的方法:像往常一样分配firstNamelastName属性,然后只为[=14定义一个getter和setter =]:

function CreateNamed(first, last) {
  this.firstName = first;
  this.lastName = last;
  Object.defineProperty(this, "fullName", {
    get: function () { return this.firstName + ' ' + this.lastName },
    set: function (name) {
      name = name.split(' ');
      if(name.length != 2) throw new Error('I cannot parse that name');
      this.firstName = name[0];
      this.lastName = name[1];
    }
  });
}

function CreateNamed(first, last) {
  this.firstName = first;
  this.lastName = last;
  Object.defineProperty(this, "fullName", {
    get: function () { return this.firstName + ' ' + this.lastName },
    set: function (name) {
      name = name.split(' ');
      if(name.length != 2) throw new Error('I cannot parse that name');
      this.firstName = name[0];
      this.lastName = name[1];
    }
  });
}

var ouput = [];

var user = new CreateNamed('bob', 'smith');
ouput.push(user.fullName); // bob smith

user.firstName = "john"; 
ouput.push(user.fullName); // john smith

user.fullName = "tony brian";
ouput.push(user.firstName); // tony
ouput.push(user.lastName); // brian

document.body.innerHTML = ouput.join('<br />');