Кто-нибудь реализовал метод Mozilla Object.toSource () для Internet Explorer и других браузеров, отличных от Gecko? Я ищу легкий способ сериализации простых объектов в строки.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Если соответствие точному формату сериализации Firefox не является вашей целью, вы можете использовать одну из библиотек сериализации / десериализации JavaScript JSON, перечисленных в http://json.org. Использование стандартной схемы, такой как JSON, может быть лучше, чем имитация проприетарного формата Gecko.
Вы можете сделать что-то вроде этого:
Object.prototype.getSource = function() {
var output = [], temp;
for (var i in this) {
if (this.hasOwnProperty(i)) {
temp = i + ":";
switch (typeof this[i]) {
case "object" :
temp += this[i].getSource();
break;
case "string" :
temp += "\"" + this[i] + "\""; // add in some code to escape quotes
break;
default :
temp += this[i];
}
output.push(temp);
}
}
return "{" + output.join() + "}";
}
Я не эксперт по JavaScript, но Object.prototype запрещен! См .: erik.eae.net/archives/2005/06/06/22.13.54 Может быть, лучше реализовать это как бесплатную функцию.
Не рекомендуется изменять прототип объекта. Также строковому типу потребуется нечто большее, чем просто экранирование \ ". Для этого потребуется экранирование \ t \ n \ r и т. д.
Замечательная идея - изменить прототип объекта, при условии, что вы знаете, как кодировать на JavaScript и не используете библиотеку (например, jQuery), которая явно выбрана неработоспособной, когда вы это делаете (в интересах повышения скорости).
См. Также Форматирование данных JavaScript / красивый принтер. Я думаю, что подпрограмма экспортирует в допустимом формате JS, поэтому ее можно вернуть с помощью eval.
[РЕДАКТИРОВАТЬ] На самом деле нет! Это нормально для быстрого дампа, но не для реальной сериализации. Я улучшил его, результат ниже:
function SerializeObject(obj, indentValue)
{
var hexDigits = "0123456789ABCDEF";
function ToHex(d)
{
return hexDigits[d >> 8] + hexDigits[d & 0x0F];
}
function Escape(string)
{
return string.replace(/[\x00-\x1F'\]/g,
function (x)
{
if (x == "'" || x == "\") return "\" + x;
return "\x" + ToHex(String.charCodeAt(x, 0));
})
}
var indent;
if (indentValue == null)
{
indentValue = "";
indent = ""; // or " "
}
else
{
indent = "\n";
}
return GetObject(obj, indent).replace(/,$/, "");
function GetObject(obj, indent)
{
if (typeof obj == 'string')
{
return "'" + Escape(obj) + "',";
}
if (obj instanceof Array)
{
result = indent + "[";
for (var i = 0; i < obj.length; i++)
{
result += indent + indentValue +
GetObject(obj[i], indent + indentValue);
}
result += indent + "],";
return result;
}
var result = "";
if (typeof obj == 'object')
{
result += indent + "{";
for (var property in obj)
{
result += indent + indentValue + "'" +
Escape(property) + "' : " +
GetObject(obj[property], indent + indentValue);
}
result += indent + "},";
}
else
{
result += obj + ",";
}
return result.replace(/,(\n?\s*)([\]}])/g, "");
}
}
indentValue может иметь значение null, "", "", "\ t" или что угодно. Если null, без отступа, вывести довольно компактный результат (можно было бы использовать меньше пробелов ...).
Я мог бы использовать массив, чтобы сложить результаты, а затем объединить их, но если у вас нет гигантских объектов, конкатенация строк должна быть достаточно хорошей ...
Также не обрабатывает циклические ссылки ...
Если вам нужно сериализовать объекты с круговыми ссылками, вы можете использовать расширение cycle.js для объекта JSON от Дугласа Крокфорда, доступное на https://github.com/douglascrockford/JSON-js. Это работает очень похоже на toSource (), хотя не выполняет сериализацию функций (но, вероятно, может быть адаптировано для использования метода toString функции).
Учтите следующее: (при использовании FireFox 3.6)
javascript:
x=function(){alert('caveat compter')};
alert(['JSON:\t',JSON.stringify(x),'\n\ntoSource():\t',x.toSource()].join(''));
который отображает:
JSON:
toSource(): (function () {alert("caveat compter");})
или даже:
javascript:
x=[];x[3]=x;
alert('toSource():\t'+x.toSource());
alert('JSON can not handle this at all and goes "infinite".');
alert('JSON:\n'+JSON.stringify(x));
который отображает:
toSource(): #1=[, , , #1#]
и сообщение "going 'infinite", откуда следует рекурсивное отступление от stackoverflow JSON.
В примерах подчеркиваются тонкости выражения, явно исключенного из представления JSON, которые отображаются с помощью toSource ().
Нелегко составить программу, воспроизводящую те же результаты для ВСЕХ случаев, что и примитив Gecko toSource (), который является исключительно мощным.
Ниже приведены несколько «движущихся целей», которые ДОЛЖНА успешно обрабатываться программой, дублирующей функцию toSource ():
javascript:
function render(title,src){ (function(objRA){
alert([ title, src,
'\ntoSource():',objRA.toSource(),
'\nJSON:',JSON.stringify(objRA) ].join('\n'));
})(eval(src));
}
render('Simple Raw Object source code:',
'[new Array, new Object, new Number, new String, ' +
'new Boolean, new Date, new RegExp, new Function]' );
render( 'Literal Instances source code:',
'[ [], 1, true, {}, "", /./, new Date(), function(){} ]' );
render( 'some predefined entities:',
'[JSON, Math, null, Infinity, NaN, ' +
'void(0), Function, Array, Object, undefined]' );
который отображает:
Simple Raw Object source code:
[new Array, new Object, new Number, new String,
new Boolean, new Date, new RegExp, new Function]
toSource():
[[], {}, (new Number(0)), (new String("")),
(new Boolean(false)), (new Date(1302637995772)), /(?:)/,
(function anonymous() {})]
JSON:
[[],{},0,"",false,"2011-04-12T19:53:15.772Z",{},null]
а затем отображает:
Literal Instances source code:
[ [], 1, true, {}, "", /./, new Date(), function(){} ]
toSource():
[[], 1, true, {}, "", /./, (new Date(1302638514097)), (function () {})]
JSON:
[[],1,true,{},"",{},"2011-04-12T20:01:54.097Z",null]
И наконец:
some predefined entities:
[JSON, Math, null, Infinity, NaN, void(0),
Function, Array, Object, undefined]
toSource():
[JSON, Math, null, Infinity, NaN, (void 0),
function Function() {[native code]}, function Array() {[native code]},
function Object() {[native code]}, (void 0)]
JSON:
[{},{},null,null,null,null,null,null,null,null]
Предыдущий анализ важен, если переводы предназначены для «использования», или менее строгие, если требуется простое безболезненное человеческое потребление для просмотра внутреннего устройства объекта. Основная функция JSON в качестве представления - это передача некоторой структурированной информации, «которая будет использоваться» между средами.
Качество функции toSource () является фактором денотационной семантики программы, влияющей, но не ограничиваясь:
вычисления в оба конца, свойства наименьшей фиксированной точки и обратные функции.
и многие, многие другие ...
Обратите внимание, что приведенные выше вопросы приобретают дополнительное значение, когда obj содержит объект исполняемого кода, например (new Function ...) ()!
Вам не обязательно использовать toSource(); оберните код для сериализации в функцию, которая возвращает структуру JSON, и используйте вместо нее function#toString():
var serialized = function () {
return {
n: 8,
o: null,
b: true,
s: 'text',
a: ['a', 'b', 'c'],
f: function () {
alert('!')
}
}
};
serialized.toString();
Чтобы пойти немного дальше: когда вы отправляете что-то - для работы - получатель должен получить это и уметь работать с этим. Итак, следующий фрагмент кода сделает свое дело - адаптированный из предыдущего ответа Элиран Малка.
// SENDER IS WRAPPING OBJECT TO BE SENT AS STRING
// object to serialize
var s1 = function (str) {
return {
n: 8,
o: null,
b: true,
s: 'text',
a: ['a', 'b', 'c'],
f: function () {
alert(str)
}
}
};
// test
s1("this function call works!").f();
// serialized object; for newbies: object is now a string and can be sent ;)
var code = s1.toString();
// RECEIVER KNOWS A WRAPPED OBJECT IS COMING IN
// you have to assign your wrapped object to somevar
eval('var s2 = ' + code);
// and then you can test somevar again
s2("this also works!").f();
Помните об использовании eval. Если весь передаваемый код принадлежит вам: не стесняйтесь использовать его (хотя он также может иметь недостатки). Если вы не знаете, откуда исходит источник: это запрещено.
Никто еще не упомянул об этом, поэтому я укажу, что полифил для Mozilla Object.toSource доступен по адресу https://github.com/oliver-moran/toSource.js
Скорее, если JSON достаточно для нужд OP, т.е. нет необходимости декомпилировать функции, разрешать циклические ссылки и т. д.