覆盖对象的setter

时间:2014-04-08 10:24:44

标签: javascript

我有一个带有getter和setter的Object,我打算保护一个属性,以便只能通过方法更新。让我们调用这个具有以下结构的对象Person

function Person(data) {
    var _name = data.name;

    this.name = function () {
        return _name;
    };
    this.setName = data.setName || function (newValue) {
        _name = newValue;
    };
}

我希望能够覆盖setName并将不同的实现传递给Person的每个实例,但我似乎无法让它发挥作用。我确定这是一个封闭问题,但我无法理解它。

鉴于以下使用方案,我做错了什么?

var p1 = new Person({
    name: "Paul",
    setName: function (newValue) {
        this._name = newValue;
    }
});
var p2 = new Person({ name: "Bob" });
p1.setName("Paul (updated)");
p2.setName("Bob (updated)");

p1永远不会更新其价值,所以总是" Paul"而p2确实并且变为" Bob(更新)"。我希望能够根据需要创建Person的任意数量的唯一实例,其中某些具有自己的setName实现,而其他实例只使用默认实例

我已尝试将data.setName包装在这样的闭包中,并设置我的自定义setName以返回值:

this.setName = data.setName ? function () {
    return (function (value) {
        value = data.setName();
    }(_name));
} : function (newValue) { _name = newValue; }

但我没有运气 - 我显然不会像我想的那样闭嘴!任何和所有的帮助总是受到赞赏。

codepen.io example here

4 个答案:

答案 0 :(得分:2)

到目前为止,我觉得这是最简单的解决方案,使用bind

function Person(data) {
    var _data = {name:data.name};

    this.name = function () {
        return _data.name;
    };
    this.setName = data.setName ? data.setName.bind(_data) : function (newValue) {
        _data.name = newValue;
    };
}

var p1 = new Person({
  name: "Paul",
  setName: function (newName) {
      this.name = newName;
  }
});
var p2 = new Person({ name: "Bob" });
p1.setName("Paul (updated)");
p2.setName("Bob (updated)");

console.log(p1.name());
console.log(p2.name());

我们不使用基元来存储名称,而是使用一个对象,我们可以使用this将其引用作为bind传递。最初,当你写this._name = newValue;时,this意味着与你想象的完全不同的东西,即你传递的对象new Person

demo

答案 1 :(得分:2)

this._name = newValue;

_name是私有变量,而不是属性。无法在this上访问它。如果您不确定差异,请查看Javascript: Do I need to put this.var for every variable in an object?

function (value) {
    value = data.setName();
}

value这是该函数范围的局部变量,而不是"引用"传入的_name变量。设置它只会在该局部变量中放置不同的值,但不会更改其他任何值。


可能的解决方案:

  • 将有权访问_name变量的setter函数传递给 验证器:

    function Person(data) {
        var _name = data.name;
    
        this.name = function () {
            return _name;
        };
        if (data.nameValidator) 
            this.setName = function(newValue) {
                _name = data.nameValidator(newValue, _name);
            };
        else
            this.setName = function (newValue) {
                _name = newValue;
            };
    }
    var p1 = new Person({
        name: "Paul",
        nameValidator: function (newValue, oldValue) {
            return (newValue /* ... */) ? newValue : oldValue;
        }
    });
    
  • 或者让验证器返回值:

    function Person(data) {
        var _name = data.name;
    
        this.name = function () {
            return _name;
        };
        this.setName = function (newValue) {
            _name = newValue;
        };
        if (data.makeNameValidator) 
            this.setName = data.makeNameValidator(this.setName);
    }
    var p1 = new Person({
        name: "Paul",
        makeNameValidator: function (nameSetter) {
            return function(newValue) {
                if (newValue) // ...
                    nameSetter(newValue);
            };
        }
    });
    
  • 或者使_name成为验证者可以写入的属性。您也可以将其放在原始的data对象上,以免在Person界面上公开它:

    function Person(data) {
        this.name = function () {
            return data.name;
        };
        if (data.setName)
            this.setName = data.setName.bind(data);
        else
            this.setName = function(newValue) {
                _name = newValue;
            };
    }
    var p1 = new Person({
        name: "Paul",
        setName: function (newValue) {
            if (newValue) // ...
                this.name = newValue;
        }
    });
    

答案 2 :(得分:0)

您认为这是this

的问题
this.setName = function (newValue) {
  if (data.setName) {
    data.setName.call(this, newValue);
  } else {
    _name = newValue;
  }
}

答案 3 :(得分:0)

您正在this._name人中设置p1,而您正在访问内部' _name函数中的变量Person(),而不是this._name。通过将this.添加到Person()类中的部分,可以轻松解决此问题。

function Person(data) {
    this._name = data.name;

    this.name = function () {
        return this._name;
    };
    this.setName = data.setName || function (newValue) {
        this._name = newValue;
    };
}

由于您在setName()函数中出现了一些错误,您的第二个示例(包装)无效。首先,您没有向data.setName()函数传递任何内容,这意味着它正在为第一个参数接收undefined。接下来,您将value 设置为返回的值,而您应该将_name设置为返回的值。试试这个:

this.setName = data.setName ? function (newValue) {
    return (function (value) {
        _name = data.setName();
    }(newValue));
} : function (newValue) { _name = newValue; }