我有一个带有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; }
但我没有运气 - 我显然不会像我想的那样闭嘴!任何和所有的帮助总是受到赞赏。
答案 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
。
答案 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; }