Реализация метода toSource() в Mozilla в Internet Explorer
Кто-нибудь реализовывал метод Mozilla Object.toSource() для Internet Explorer и других браузеров, отличных от Gecko? Я ищу легкий способ сериализации простых объектов в строки.
8 ответов
Учтите следующее: (при использовании 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 #]
и "идущее" бесконечное "сообщение, которое следует за рекурсивным отступлением JSON в stackru.
В примерах подчеркиваются тонкости выражения, явно исключенные из представления 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: [новый массив, новый объект, новый номер, новая строка, новый логический, новая дата, новый RegExp, новая функция] к источнику(): [[], {}, (новый номер (0)), (новая строка ("")), (новый логический (false)), (новая дата (1302637995772)), /(?:)/, (функция анонимная () {})] JSON: [[],{},0,"", ложно,"2011-04-12T19:53:15.772Z",{}, нулевое]
а затем отображает:
Исходный код буквальных экземпляров: [ [], 1, true, {}, "", /./, new Date(), function(){} ] к источнику(): [[], 1, true, {}, "", /./, (новая дата (1302638514097)), (function () {})] JSON: [[],1, правда,{},"",{},"2011-04-12T20:01:54.097Z", нулевая]
И наконец:
некоторые предопределенные объекты: [JSON, Math, ноль, бесконечность, NaN, void(0), Функция, Массив, Объект, неопределенный] к источнику(): [JSON, Math, ноль, бесконечность, NaN (void 0), function Function() {[собственный код]}, функция Array() {[собственный код]}, function Object() {[собственный код]}, (void 0)] JSON: [{},{}, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL]
Предыдущий анализ важен, если переводы "должны быть использованы" или менее строг, если требуется простое и мягкое потребление человеком для просмотра внутренних объектов объекта. Основная особенность JSON, как представление, - это передача некоторой структурированной информации, "используемой" между средами.
Качество функции toSource () является фактором денотационной семантики программы, влияющим, но не ограниченным:
вычисления туда-обратно, свойства наименьшей фиксированной точки и обратные функции.
- Повторяется ли преобразование кода в статическое состояние?
- Имеет ли obj.toSource() == eval(eval(eval(obj.toSource()). ToSource ()). ToSource ()). ToSource()?
- Имеет ли смысл подумать, есть ли obj == eval(obj.toSource())?
- В результате отмены преобразования получается не просто похожий объект, а ИДЕНТИЧНЫЙ?
Это загруженный вопрос с глубокими последствиями при клонировании оперативного объекта.
и многое, многое другое...
Обратите внимание, что приведенные выше вопросы приобретают дополнительное значение, когда obj содержит объект исполняемого кода, такой как (новая функция...)()!
Если соответствие точного формата сериализации Firefox не является вашей целью, вы можете использовать одну из библиотек JavaScript JSON для сериализации / десериализации, перечисленных на http://json.org/. Использование стандартной схемы, такой как JSON, может быть лучше, чем имитация проприетарного формата Gecko.
Если вам нужно сериализовать объекты с циклическими ссылками, вы можете использовать расширение cycle.js для объекта JSON Дугласа Крокфорда, которое доступно по адресу https://github.com/douglascrockford/JSON-js. Это работает очень похоже на toSource(), хотя и не сериализует функции (но, вероятно, может быть адаптировано для использования метода toString функции).
Вы могли бы сделать что-то вроде этого:
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() + "}";
}
Чтобы продвинуться немного дальше: когда вы отправляете что-то - для работы - получатель должен получить это и иметь возможность работать с этим. Так что следующий Eliran Malka кода поможет, адаптированный из предыдущего ответа Eliran Malka.
// 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
, Если вам принадлежит весь передаваемый код: не стесняйтесь использовать его (хотя он также может иметь недостатки). Если вы не знаете, откуда исходит источник: это нет-нет.
Вам не нужно использовать 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();
Смотрите живое демо на jsFiddle.
Смотрите также JavaScript форматирование данных / симпатичный принтер. Я думаю, что рутина экспортируется в допустимом формате JS, поэтому ее можно вернуть обратно.
[ПРАВКА] На самом деле, нет! Это нормально для быстрого дампа, но не для реальной сериализации. Я улучшил это, результат ниже:
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, "$1$2");
}
}
indentValue может быть нулевым, "", " ", "\t" или любым другим. Если ноль, без отступа, выведите довольно компактный результат (можно использовать меньше пробелов...).
Я мог бы использовать массив для суммирования результатов, а затем соединить их, но если у вас нет гигантских объектов, конкатенация строк должна быть достаточно хорошей...
Также не обрабатывает циклические ссылки...
Никто еще не упомянул об этом, поэтому я укажу, что для Mozilla есть полифилл Object.toSource
на https://github.com/oliver-moran/toSource.js