我想在代码中实现类似 down 的行为:
function Foo(name) {
this.name = name;
};
var myFoo = new Foo('myName');
myFoo.name('newMyName'); // sets myFoo.name = 'newMyName'
myFoo.name(); // returns 'myName'
但很明显,在那种情况下,我用名称函数覆盖了名称属性。无论如何有可能实现该功能?
在谈论 javascript 中的 getter 和 setter 时,您可能在谈论两个概念之一:
问题中的代码说明了这种情况。在这种情况下,对象的属性很简单,可以是对象或函数的属性。 Javascript 在同一个命名空间中跟踪两者。实际上,函数只是 javascript 中的对象,因此没有像 C 语言中那样为函数单独命名空间的概念。
在这种情况下,“getters”和“setters”只是常规函数,因此需要单独存储值。围绕这个有几种策略。
一种是使用Java中常见的隐式
getSomething()
和setSomething()
风格的函数。这允许您从属性名称中消除 getter 和 setter 的歧义,因为 getter 和 setter 在名称中添加了单词“get”和“set”。
第二个策略是你在问题中写的那个。在这种情况下,您需要将属性存储在另一个名称中,以免与 getter/setter 共享相同的名称。
第三种策略是将值存储在闭包中:
function Foo (name) {
var name = name;
this.name = function (str) {
if (str !== undefined) name = str;
return name;
}
}
请注意,在上面的代码中,值存储在
name
中,但 getter/setter 是 this.name
,这是一个完全不同的变量。这允许您的示例代码按预期工作:
var me = new Foo('Mark');
me.name(); // returns Mark
me.name('Andy'); // sets name to Andy
这是遵循 ECMAscript 5 规范的较新版本的 javascript 的功能。此功能允许属性在读取或写入代码时执行代码,类似于 DOM 对象的
.innerHTML
属性在您为其分配内容时调用 HTML 解析器的方式。
getter 和 setter 的语法类似于函数,但引入了
get
和 set
关键字来代替 function
.
具有 getter 和 setter 的属性的简单示例:
var me = {
first_name : "",
last_name : "",
get name() {
return this.first_name + " " + this.last_name;
},
set name(str) {
var n = str.split(/\s+/);
this.first_name = n.shift();
this.last_name = n.join(' ');
}
}
上面的代码允许您将获取和设置
first_name
和 last_name
的函数视为变量而不是函数。要使用 name
getter 和 setter,您只需执行以下操作:
me.name = "James Bond";
alert(me.first_name); // should alert James
alert(me.last_name); // should alert Bond
me.last_name = "Dean";
alert(me.name); // should alert James Dean
使用javascript的get/set机制,不能在对象中存储同名的值例如:
var foo = {
set bar(x) {this.bar=x}
}
上面的代码将编译但尝试设置 bar:
foo.bar = 1
将由于无限循环导致堆栈溢出 - setter 中的this.bar=
将再次调用 setter.
如果你想使用与属性同名的 JavaScript getter/setter,例如要拦截某些设置器以实现副作用,您可以为您的对象创建一个
Proxy
。
function editableProxy (myObj) {
return new Proxy(myObj, {
toJSON: () => myObj,
get: function (target, prop) {
return Reflect.get(myObj, prop);
},
set: function (target, prop, receiver) {
if (prop === 'billTo') {
myObj.billToId = receiver?.id;
}
return Reflect.set(myObj, prop, receiver);
},
});
};
所有吸气剂工作正常。设置器正常工作,但如果你设置一个
billTo
它也会设置一个billToId。
let da = {id:123}
let wrapped = editableProxy(da)
let id = wrapped.id // 123
wrapped.id=234
wrapped.id===da.id // true
wrapped.billTo={id:567,name:'Big Bad Bill'} // triggers setter side effect
wrapped.billToId // 567