Javascript: 在对象闭包中使用访问器属性
Javascript: Using accessor properties in object closures
我最近通过阅读 this article 了解了如何使用函数将对象组合在一起。接下来,我得到了这段代码:
function withFlying(o) {
let _isFlying = false;
return {
...o,
fly () {
_isFlying = true;
},
land () {
_isFlying = false;
},
isFlying () {
return _isFlying
}
}
};
function withWalking(o) {
let isWalking = false;
return {
...o,
startWalking() {
isWalking = true;
return this
},
stopWalking() {
isWalking = false;
return this
},
isWalking: () => isWalking
}
}
const bird = withWalking(withFlying({}))
这里一切正常。但是,我希望能够将 isFlying
作为 属性 而不是函数来调用:
// current (working)
bird.isFlying() // return value of `_isFlying`
// desired
bird.isFlying // return value of `_isFlying`
我知道 get
和 set
是可以在对象字面量中使用的关键字,所以我尝试了这个:
function withFlying(o) {
let _isFlying = false
return {
...
get isFlying () {
return _isFlying
}
}
}
但是在使用其他函数更新后它没有显示正确的值。我认为 get
属性 是一个函数,闭包的应用类似于其他函数。我这个假设错了吗? get
是否存在我不理解的潜在行为,我正在尝试以我现在的方式实现可能的目标吗?
这是我尝试使用的代码片段:
function withFlying(o) {
let _isFlying = false;
return {
...o,
fly () {
_isFlying = true;
},
land () {
_isFlying = false;
},
valueOf_isFlying() {
return _isFlying;
},
get isFlying () {
return _isFlying
}
}
};
function withWalking(o) {
let isWalking = false;
return {
...o,
startWalking() {
isWalking = true;
return this
},
stopWalking() {
isWalking = false;
return this
},
isWalking: () => isWalking
}
}
const bird = withWalking(withFlying({}))
// desired
console.log(bird.isFlying) // _isFlying starts false
bird.fly() // should set _isFlying to true
console.log(bird.isFlying) // still returns false
console.log(bird.valueOf_isFlying()) // shows _isFlying is true
问题是当您创建新对象时,您正在使用展开符号从原始对象复制属性:
return {
...o,
// ...
};
问题在于它复制了访问器属性的 当时-当前值,而不是访问器 属性 的定义。你可以在这里看到:
const obj1 = {
get example() {
return 42;
}
};
console.log("Notice that the property descriptor is for an accessor property:");
console.log(Object.getOwnPropertyDescriptor(obj1, "example"));
const obj2 = {...obj1};
console.log("Notice that the property descriptor is for a simple data property:");
console.log(Object.getOwnPropertyDescriptor(obj2, "example"));
.as-console-wrapper {
max-height: 100% !important;
}
这很像你所做的:
for (const key of Object.keys(o) {
newObject[key] = e[key];
}
e[key]
获取 属性 的当前值,而不是 属性.
的定义
要修复它,请使用 Object.getOwnPropertyDesciptors
获取属性的描述符,并使用 Object.defineProperties
在新对象上定义相同的属性。由于您至少在两个地方这样做(并添加了更多属性),您可能需要一个效用函数:
function assignPropertyDescriptors(target, obj, updates) {
// B
return Object.defineProperties(
// A
Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(obj)
),
Object.getOwnPropertyDescriptors(updates)
);
}
"A" Object.defineProperties
调用复制原始对象的 属性 描述符并将它们应用于新对象。 "B" Object.defineProperties
调用也将您添加到该新对象的对象应用。
但是让我们将其概括为一个循环,类似于 Object.assign
(因此得名 assignPropertyDescriptors
):
function assignPropertyDescriptors(target, ...updates) {
for (const update of updates) {
Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(update)
);
}
return target;
}
withFlying
和 withWalking
将使用该辅助函数,例如:
function withFlying(o) {
let _isFlying = false;
return assignPropertyDescriptors({}, o, {
fly () {
_isFlying = true;
},
land () {
_isFlying = false;
},
get isFlying () {
return _isFlying
}
});
};
这是一个完整的例子:
function assignPropertyDescriptors(target, ...updates) {
for (const update of updates) {
Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(update)
);
}
return target;
}
function withFlying(o) {
let _isFlying = false;
return assignPropertyDescriptors({}, o, {
fly () {
_isFlying = true;
},
land () {
_isFlying = false;
},
get isFlying () {
return _isFlying
}
});
};
function withWalking(o) {
let isWalking = false;
return assignPropertyDescriptors({}, o, {
startWalking() {
isWalking = true;
return this
},
stopWalking() {
isWalking = false;
return this
},
isWalking: () => isWalking
});
}
const bird = withWalking(withFlying({}))
console.log(bird.isFlying) // _isFlying starts false
bird.fly() // should set _isFlying to true
console.log(bird.isFlying) // _isFlying is true
我最近通过阅读 this article 了解了如何使用函数将对象组合在一起。接下来,我得到了这段代码:
function withFlying(o) {
let _isFlying = false;
return {
...o,
fly () {
_isFlying = true;
},
land () {
_isFlying = false;
},
isFlying () {
return _isFlying
}
}
};
function withWalking(o) {
let isWalking = false;
return {
...o,
startWalking() {
isWalking = true;
return this
},
stopWalking() {
isWalking = false;
return this
},
isWalking: () => isWalking
}
}
const bird = withWalking(withFlying({}))
这里一切正常。但是,我希望能够将 isFlying
作为 属性 而不是函数来调用:
// current (working)
bird.isFlying() // return value of `_isFlying`
// desired
bird.isFlying // return value of `_isFlying`
我知道 get
和 set
是可以在对象字面量中使用的关键字,所以我尝试了这个:
function withFlying(o) {
let _isFlying = false
return {
...
get isFlying () {
return _isFlying
}
}
}
但是在使用其他函数更新后它没有显示正确的值。我认为 get
属性 是一个函数,闭包的应用类似于其他函数。我这个假设错了吗? get
是否存在我不理解的潜在行为,我正在尝试以我现在的方式实现可能的目标吗?
这是我尝试使用的代码片段:
function withFlying(o) {
let _isFlying = false;
return {
...o,
fly () {
_isFlying = true;
},
land () {
_isFlying = false;
},
valueOf_isFlying() {
return _isFlying;
},
get isFlying () {
return _isFlying
}
}
};
function withWalking(o) {
let isWalking = false;
return {
...o,
startWalking() {
isWalking = true;
return this
},
stopWalking() {
isWalking = false;
return this
},
isWalking: () => isWalking
}
}
const bird = withWalking(withFlying({}))
// desired
console.log(bird.isFlying) // _isFlying starts false
bird.fly() // should set _isFlying to true
console.log(bird.isFlying) // still returns false
console.log(bird.valueOf_isFlying()) // shows _isFlying is true
问题是当您创建新对象时,您正在使用展开符号从原始对象复制属性:
return {
...o,
// ...
};
问题在于它复制了访问器属性的 当时-当前值,而不是访问器 属性 的定义。你可以在这里看到:
const obj1 = {
get example() {
return 42;
}
};
console.log("Notice that the property descriptor is for an accessor property:");
console.log(Object.getOwnPropertyDescriptor(obj1, "example"));
const obj2 = {...obj1};
console.log("Notice that the property descriptor is for a simple data property:");
console.log(Object.getOwnPropertyDescriptor(obj2, "example"));
.as-console-wrapper {
max-height: 100% !important;
}
这很像你所做的:
for (const key of Object.keys(o) {
newObject[key] = e[key];
}
e[key]
获取 属性 的当前值,而不是 属性.
要修复它,请使用 Object.getOwnPropertyDesciptors
获取属性的描述符,并使用 Object.defineProperties
在新对象上定义相同的属性。由于您至少在两个地方这样做(并添加了更多属性),您可能需要一个效用函数:
function assignPropertyDescriptors(target, obj, updates) {
// B
return Object.defineProperties(
// A
Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(obj)
),
Object.getOwnPropertyDescriptors(updates)
);
}
"A" Object.defineProperties
调用复制原始对象的 属性 描述符并将它们应用于新对象。 "B" Object.defineProperties
调用也将您添加到该新对象的对象应用。
但是让我们将其概括为一个循环,类似于 Object.assign
(因此得名 assignPropertyDescriptors
):
function assignPropertyDescriptors(target, ...updates) {
for (const update of updates) {
Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(update)
);
}
return target;
}
withFlying
和 withWalking
将使用该辅助函数,例如:
function withFlying(o) {
let _isFlying = false;
return assignPropertyDescriptors({}, o, {
fly () {
_isFlying = true;
},
land () {
_isFlying = false;
},
get isFlying () {
return _isFlying
}
});
};
这是一个完整的例子:
function assignPropertyDescriptors(target, ...updates) {
for (const update of updates) {
Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(update)
);
}
return target;
}
function withFlying(o) {
let _isFlying = false;
return assignPropertyDescriptors({}, o, {
fly () {
_isFlying = true;
},
land () {
_isFlying = false;
},
get isFlying () {
return _isFlying
}
});
};
function withWalking(o) {
let isWalking = false;
return assignPropertyDescriptors({}, o, {
startWalking() {
isWalking = true;
return this
},
stopWalking() {
isWalking = false;
return this
},
isWalking: () => isWalking
});
}
const bird = withWalking(withFlying({}))
console.log(bird.isFlying) // _isFlying starts false
bird.fly() // should set _isFlying to true
console.log(bird.isFlying) // _isFlying is true