Разомнул мозги.
Метод может не создавать полные копии объектов в объектах, если в оригинале он null - просто пишет в результирующий объект ссылку.

Код AS3:
package {
import artshlagin.utils.Tracer;
import flash.display.Sprite;
import flash.events.Event;
/**
* ...
* @author Artem Shlagin
*/
public class Main extends Sprite {
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
var objOriginal:Object = {
a: "a",
b: "1",
c: {
sub1: false,
sub2: {
x:10,
y:20,
z:null
}
}
}
var objChanged:Object = {
a: "a",
b: "2",
c: {
sub1: false,
sub2: {
x:10,
y:20,
z:{
z_param: [1,2,3,4, "last"]
}
}
}
}
var objResult:Object = theSuperFunction(objOriginal, objChanged);
Tracer.fullTraceObject(objResult);
}
private function theSuperFunction(objOriginal:Object, objChanged:Object):Object {
var result:Object = { };
if (!objOriginal) return objChanged;
for (var name:String in objOriginal) {
if (!(name in objChanged)) continue;
if (isComposite(objOriginal[name])) {
if (!isComposite(objChanged[name])) result[name] = objChanged[name];
else{
var temp:Object = theSuperFunction(objOriginal[name], objChanged[name]);
if (!isEmpty(temp)) result[name] = temp;
}
}
else {
if (objChanged[name] !== objOriginal[name]) result[name] = objChanged[name];
}
}
return result;
}
/**
* Что-то не пришло в голову лучшего способа проверки на хэш
* @param object
* @return
*/
private function isComposite(object:*):Boolean {
return typeof object === "object";
}
private function isEmpty(temp:Object):Boolean {
for (var name:String in temp) {
return false;
}
return true;
}
}
}
Код трейсера:

Код AS3:
package artshlagin.utils
{
/**
* ...
* @author Artem Shlagin
*/
public class Tracer
{
public static var traceFunction:Function = trace;
public static var nameDelimiter:String = " => ";
public function Tracer()
{
throw new Error("Class is static");
}
public static function fullTraceObject(object:Object):void {
recoursiveTrace(object);
}
private static function recoursiveTrace(o:Object, startValue:int = 0):void {
for (var name:Object in o)
{
var otst:String = "";
if (startValue > 0) {
var i:int = startValue;
while (i--) otst += " ";
}
traceFunction.call(null, otst + name + nameDelimiter + o[name]);
if ((typeof o[name]) === "object") recoursiveTrace(o[name], startValue+1);
}
}
}
}
Результат:

Код:
b => 2
c => [object Object]
sub2 => [object Object]
z => [object Object]
z_param => 1,2,3,4,last
0 => 1
1 => 2
2 => 3
3 => 4
4 => last
Но не ручаюсь за правильность работы во всех ситуациях.