Javascript 重写对象上的setter
我有一个带有getter和setter的对象,我打算在其中保护一个属性,以便它只能通过一个方法更新。我们将此对象称为Person,其结构如下:Javascript 重写对象上的setter,javascript,Javascript,我有一个带有getter和setter的对象,我打算在其中保护一个属性,以便它只能通过一个方法更新。我们将此对象称为Person,其结构如下: function Person(data) { var _name = data.name; this.name = function () { return _name; }; this.setName = data.setName || function (newValue) { _n
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你认为这是个问题吗
你认为这是个问题吗 您正在p1 Person中设置此。_name,而您正在Person函数中访问“内部”变量_name,而不是此。_name。通过添加此项,可以很容易地解决此问题。在你的个人课上扮演角色 第二个示例是包装,由于在setName函数中出现了一些错误,因此无法工作。首先,您没有向data.setName函数传递任何内容,这意味着它正在接收第一个参数的undefined。接下来,将value设置为返回值,而应该将_name设置为返回值。请尝试以下方法:
this.setName = data.setName ? function (newValue) {
return (function (value) {
_name = data.setName();
}(newValue));
} : function (newValue) { _name = newValue; }
您正在p1 Person中设置此。_name,而您正在Person函数中访问“内部”变量_name,而不是此。_name。通过添加此项,可以很容易地解决此问题。在你的个人课上扮演角色
第二个示例是包装,由于在setName函数中出现了一些错误,因此无法工作。首先,您没有向data.setName函数传递任何内容,这意味着它正在接收第一个参数的undefined。接下来,将value设置为返回值,而应该将_name设置为返回值。请尝试以下方法:
this.setName = data.setName ? function (newValue) {
return (function (value) {
_name = data.setName();
}(newValue));
} : function (newValue) { _name = newValue; }
我觉得这是迄今为止最简单的解决方案,使用bind: 我们不使用原语来存储名称,而是使用一个对象,我们可以使用bind将其引用作为该对象传递。最初,当您编写此文件时。_name=newValue;,这意味着与你所想的完全不同的东西,即你传递给新的人的物体
我觉得这是迄今为止最简单的解决方案,使用bind: 我们不使用原语来存储名称,而是使用一个对象,我们可以使用bind将其引用作为该对象传递。最初,当您编写此文件时。_name=newValue;,这意味着与你所想的完全不同的东西,即你传递给新的人的物体 _name是一个私有变量,而不是属性。无法在此服务器上访问它。如果您不确定差异,请查看 这里的值是该函数作用域的局部变量,而不是对传入的_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);
};
}
});
或者将_命名为验证器可以写入的属性。您还可以将其放在原始数据对象上,以避免在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;
}
});
_name是一个私有变量,而不是属性。无法在此服务器上访问它。如果您不确定差异,请查看
这里的值是该函数作用域的局部变量,而不是对传入的_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);
};
}
});
或者将_命名为验证器可以写入的属性。您还可以将其放在原始数据对象上,以避免在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;
}
});
我也是,但不幸的是这不起作用。但是我已经用这个更新了代码笔。对不起,\u名称不能通过这个访问,所以这不是解决方案。这是一个非常棘手的问题,因为只有在Person范围内定义的函数才有权访问_name。我也是,但不幸的是,这不起作用。但是我已经用这个更新了代码笔。对不起,\u名称不能通过这个访问,所以这不是解决方案。这是一个非常棘手的问题,因为只有在Person范围内定义的函数才能访问_name
在我试图避免-我知道我目前的设计可能不适合我试图实现的-但这就是为什么我在这里:oTry使用你的第二个想法和我提供的第二个例子,它应该工作;暴露_name是我试图避免的——我知道我目前的设计可能不适合我试图实现的目标——但这就是为什么我在这里:oTry使用你的第二个想法和我提供的第二个示例,它应该会起作用;我现在明白了,在我的头脑中,我的设计过于复杂了!,这是现在的工作,我已经更新了代码笔,谢谢!我不会说我的任何设计都不复杂:-哈哈,这是真的,尽管我的意思是在我的脑海中,我想象着替换整个方法签名-参数、返回类型和工作,所有这些都在一个闭包内。。。然后它击中了我,我在跳出框框思考。我现在明白了,我的设计在我的头脑中过于复杂了!,这是现在的工作,我已经更新了代码笔,谢谢!我不会说我的任何设计都不复杂:-哈哈,这是真的,尽管我的意思是在我的脑海中,我想象着替换整个方法签名-参数、返回类型和工作,所有这些都在一个闭包内。。。然后它击中了,我在跳出框框思考。@PaulAldred Bann虽然你已经接受了答案,但我鼓励你看看这个,我认为它很优雅,非常接近你最初的想法,在我看来,JavaScript的一个非常基本的核心特性是有效的。虽然我没有看到你的答案,但它也在现在被接受的答案中+1!@莫斯,我错过了这个!我喜欢将私有变量更改为对象并作为作用域传递给自定义方法的方式。但是,在实际应用程序中,在I$扩展通过参数传递的值的情况下,我需要将Person作为作用域传递。因此,我使用.bind调用@Bergi的解决方案。@PaulAldred Bann虽然你已经接受了答案,但我鼓励你看看这个,我认为它很优雅,非常接近你最初的想法,在我看来,JavaScript的一个非常基本的核心特性是有效的。虽然我没有看到你的答案,但它也在现在被接受的答案中+1!@莫斯,我错过了这个!我喜欢将私有变量更改为对象并作为作用域传递给自定义方法的方式。但是,在实际应用程序中,在I$扩展通过参数传递的值的情况下,我需要将Person作为作用域传递。因此,我使用.bind调用@Bergi的解决方案。
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;
}
});