#javascript #loops
#javascript #циклы
Вопрос:
У меня есть большой объект (у него около 200 свойств), и я хочу распечатать его следующим образом:
[property1: alice, property2: bob, property3: 42, ...]
Если свойство является функцией, я хочу, чтобы оно печатало код функции, а если это массив, я хочу, чтобы он печатал каждый элемент этого массива. Кроме того, если свойство является объектом, оно также должно печатать его свойства и так далее…
Я пытался реализовать это рекурсивно, но, конечно, стек вызовов стал слишком большим довольно быстро. Затем я перешел к итеративной реализации с использованием стека. Вот что у меня получилось:
function getPropertyString(obj) {
var res = "";
var stack = [];
stack.push(obj);
while(stack.length > 0){
var object = stack.pop();
res = "[";
for(var prop in object) {
if(prop == null) continue;
if(typeof object[prop] === 'object') {
stack.push(object[prop]);
} else {
res = prop ": "
object[prop].toString().replace(/[trn]/g, "") ", ";
}
}
res = "],";
}
return res;
}
Это отлично работает, если у вас есть объект, подобный
var a = {
b : {
c : "hello",
d : "world"
},
e : "alice",
f : "bob",
g : function() {
console.log("hello");
},
h : [1, 2, 3]
}
но, допустим, вы модифицируете a
так, чтобы a.x = {}; a.x.prototype = a;
. Тогда моя функция застряла бы в бесконечном цикле.
Как я мог обойти это?
Комментарии:
1. Это не имеет ничего общего с цепочкой прототипов (или
.prototype
свойствами), циклические ссылки всегда могут произойти. (простейший пример:var a = {}; a.x = a;
)2. Спасибо, что указали на это. Должен ли я тогда изменить заголовок?
Ответ №1:
Создайте массив объектов, которые были обработаны из стека, и не обрабатывайте их снова: (Я отметил строки, которые я добавил для этого)
function getPropertyString(obj) {
var res = "";
var stack = [];
var objectHistory = []; // added this
stack.push(obj);
while(stack.length > 0){
var object = stack.pop();
if (objectHistory.indexOf(object) != -1) continue; // added this
objectHistory.push(object); // added this
res = "[";
for(var prop in object) {
if(prop == null) continue;
if(typeof object[prop] === 'object') {
stack.push(object[prop]);
} else {
res = prop ": "
object[prop].toString().replace(/[trn]/g, "") ", ";
}
}
res = "],";
}
return res;
}
var a = {
b : {
c : "hello",
d : "world"
},
e : "alice",
f : "bob",
g : function() {
console.log("hello");
},
h : [1, 2, 3]
};
a.x = {
i: "I am X"
};
a.x.prototype = a;
console.log(getPropertyString(a));
Комментарии:
1. Просто. Мне это нравится!
2. Всегда приятно порадовать простым решением :-). Если этот ответ работает для вас, пожалуйста, не забудьте пометить его как правильный.
Ответ №2:
Как насчет JSON.stringify
того, чтобы сначала передать функцию в качестве 2-го аргумента (так называемый ‘replacer’), чтобы также преобразовать методы в строки, потому что по умолчанию JSON.stringify
функции отбрасываются. Таким образом, у вас будут все свойства, и если вы установите «бесконечный цикл», то JSON предупредит вас об этом.
Комментарии:
1. Ну, как я уже сказал, метод работает для объекта
a
(он также печатает метод и т. Д.). И мне нужно не оповещение, а функция, которая обрабатывает этот случай «цикла».