gpt4 book ai didi

Javascript:在对象闭包中使用访问器属性

转载 作者:行者123 更新时间:2023-12-01 15:43:55 27 4
gpt4 key购买 nike

我最近通过阅读 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`

我知道 getset 是可以在对象字面量中使用的关键字,所以我尝试了这个:

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;
}

withFlyingwithWalking 将使用该辅助函数,例如:

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

关于Javascript:在对象闭包中使用访问器属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61188890/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com