我想在代码中实现类似 down 的行为:
function Foo(name) {
this.name = name;
};
var myFoo = new Foo('myName');
myFoo.name('newMyName'); // sets myFoo.name = 'newMyName'
myFoo.name(); // returns 'myName'
但很明显,在这种情况下,我将使用 name 函数覆盖 name 属性。无论如何有可能实现该功能?
我想在代码中实现类似 down 的行为:
function Foo(name) {
this.name = name;
};
var myFoo = new Foo('myName');
myFoo.name('newMyName'); // sets myFoo.name = 'newMyName'
myFoo.name(); // returns 'myName'
但很明显,在这种情况下,我将使用 name 函数覆盖 name 属性。无论如何有可能实现该功能?
在谈论 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/setterthis.name
是一个完全不同的变量。这允许您的示例代码按预期工作:
var me = new Foo('Mark');
me.name(); // returns Mark
me.name('Andy'); // sets name to Andy
这是遵循 ECMAscript 5 规范的较新版本的 javascript 的一个功能。此功能允许属性在读取或写入时执行代码,类似于.innerHTML
DOM 对象的属性在您为其分配内容时调用 HTML 解析器的方式。
getter 和 setter 的语法类似于函数,但引入了get
andset
关键字来代替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
会因为无限循环而导致堆栈溢出 - this.bar=
setter 内部将再次调用 setter。
如果您想使用与属性同名的 JavaScript getter/setter,例如拦截某些 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