Копировать объект с результатами геттеров
У меня есть объект, который содержит геттер.
myObject {
id: "MyId",
get title () { return myRepository.title; }
}
myRepository.title = "MyTitle";
Я хочу получить объект как:
myResult = {
id: "MyId",
title: "MyTitle"
}
Я не хочу копировать геттер, поэтому:
myResult.title; // Returns "MyTitle"
myRepository.title = "Another title";
myResult.title; // Should still return "MyTitle"
Я попробовал:
- $.extend (): Но он не перебирает получателей. http://bugs.jquery.com/ticket/6145
- Итерация свойств, как предлагается здесь, но она не перебирает геттеры.
- Как я использую angular, используя Angular.forEach, как предлагается здесь. Но я получаю только свойства, а не добытчики.
Любая идея? Спасибо!
Обновление Я устанавливал получатель, используя Object.defineProperty как:
"title": { get: function () { return myRepository.title; }},
Как можно прочитать в документе:
enumerable true тогда и только тогда, когда это свойство обнаруживается при перечислении свойств соответствующего объекта. По умолчанию false.
Установка перечислимого: правда, исправить проблему.
"title": { get: function () { return myRepository.title; }, enumerable: true },
3 ответа
$.extend
делает именно то, что вы хотите. (Обновление: с тех пор вы сказали, что хотите также и неперечислимые свойства, поэтому он не делает то, что вы хотите; смотрите вторую часть этого ответа ниже, но я оставлю первый бит для других.) Ошибка не говорит, что полученный объект не будет иметь title
свойство, это говорит о том, что результирующий объект title
собственность не будет добытчиком, что идеально подходит для того, что вы сказали, что хотели.
Пример с правильным синтаксисом получателя:
// The myRepository object
var myRepository = { title: "MyTitle" };
// The object with a getter
var myObject = {
id: "MyId",
get title() { return myRepository.title; }
};
// The copy with a plain property
var copy = $.extend({}, myObject);
// View the copy (although actually, the result would look
// the same either way)
snippet.log(JSON.stringify(copy));
// Prove that the copy's `title` really is just a plain property:
snippet.log("Before: copy.title = " + copy.title);
copy.title = "foo";
snippet.log("After: copy.title = " + copy.title);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Синтаксические исправления:
Добавлено недостающее
var
,=
, а также;
Удалено дублирующее свойство
title
Исправлен синтаксис объявления геттера
Если вы хотите включить не перечисляемые свойства, вам нужно использовать Object.getOwnPropertyNames
потому что они не будут появляться в for-in
петли, Object.keys
, или же $.extend
(независимо от того, являются ли они "добытчиками" или обычными свойствами):
// The myRepository object
var myRepository = { title: "MyTitle" };
// The object with a getter
var myObject = {
id: "MyId"
};
Object.defineProperty(myObject, "title", {
enumerable: false, // it's the default, this is just for emphasis,
get: function() {
return myRepository.title;
}
});
snippet.log("$.extend won't visit non-enumerable properties, so we only get id here:");
snippet.log(JSON.stringify($.extend({}, myObject)));
// Copy it
var copy = Object.getOwnPropertyNames(myObject).reduce(function(result, name) {
result[name] = myObject[name];
return result;
}, {});
// View the copy (although actually, the result would look
// the same either way)
snippet.log("Our copy operation with Object.getOwnPropertyNames does, though:");
snippet.log(JSON.stringify(copy));
// Prove that the copy's `title` really is just a plain property:
snippet.log("Before: copy.title = " + copy.title);
copy.title = "foo";
snippet.log("After: copy.title = " + copy.title);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Прежде всего, исправьте ваш синтаксис, хотя он, вероятно, хорош в вашем реальном коде:
myObject = {
id: "MyId",
get title () { return myRepository.title; }
}
Теперь к ответу.:)
Вы можете просто использовать for..in
цикл, чтобы получить все свойства, а затем сохранить их как есть:
var newObj = {};
for (var i in myObject) {
newObj[i] = myObject[i];
}
Нет JQuery, Angular, любые другие плагины, необходимые!
У меня была такая же проблема, но в TypeScript и метод, упомянутый TJ Crowder, не работал.
Что сработало, так это следующее:
Типскрипт :
function copyObjectIncludingGettersResult(originalObj: any) {
//get the properties
let copyObj = Object.getOwnPropertyNames(originalObj).reduce(function (result: any, name: any) {
result[name] = (originalObj as any)[name];
return result;
}, {});
//get the getters values
let prototype = Object.getPrototypeOf(originalObj);
copyObj = Object.getOwnPropertyNames(prototype).reduce(function (result: any, name: any) {
//ignore functions which are not getters
let descriptor = Object.getOwnPropertyDescriptor(prototype, name);
if (descriptor?.writable == null) {
result[name] = (originalObj as any)[name];
}
return result;
}, copyObj);
return copyObj;
}
Версия Javascript:
function copyObjectIncludingGettersResult(originalObj) {
//get the properties
let copyObj = Object.getOwnPropertyNames(originalObj).reduce(function (result, name) {
result[name] = originalObj[name];
return result;
}, {});
//get the getters values
let prototype = Object.getPrototypeOf(originalObj);
copyObj = Object.getOwnPropertyNames(prototype).reduce(function (result,name) {
let descriptor = Object.getOwnPropertyDescriptor(prototype, name);
if (descriptor?.writable == null) {
result[name] = originalObj[name];
}
return result;
}, copyObj);
return copyObj;
}