Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

create structured clone of Proxy

I have a class that returns a Proxy from the constructor. When I try to store instances of this class in IndexedDB, or send the object using window.postMessage(), I receive an error stating that the object could not be cloned. It appears that the structured clone algorithm cannot handle Proxy objects.

The following code demonstrates the error:

class MyClass {
  constructor() {
    return new Proxy(this, {
      set(target, prop, val, receiver) {
        console.log(`"${prop}" was set to "${val}"`);
        return Reflect.set(target, prop, val, receiver);
      }
    });
  }
}

const obj = new MyClass;

try {
  window.postMessage(obj,'*');
} catch(err) {
  console.error(err);

}

Can anyone suggest a workaround for this problem? I see two potential solutions, but I don't know how I might implement them:

  1. Do not return a Proxy from the constructor, but maintain the Proxy functionality within the class declaration somehow.

  2. Alter the Proxy instance so that it works with the structured clone algorithm.

EDIT: The following, simpler code also demonstrates the structured clone error:

const p = new Proxy({}, {});
window.postMessage(p, '*');
like image 938
dwhieb Avatar asked May 22 '17 17:05

dwhieb


1 Answers

You can save the original, non-proxied object in a class property, and use it when you want to pass it to postMessage. You can change the constructor to have an optional parameter which will be passed to the proxy instead of this. This way you can recreate the object by passing it to the constructor.

class MyClass {
  constructor(original = this) {
    this.original = original;
    return new Proxy(original, {
      set(target, prop, val, receiver) {
        console.log(`"${prop}" was set to "${val}"`);
        return Reflect.set(target, prop, val, receiver);
      }
    });
  }
  export() {
    return this.original;
  }
  static import(original) {
    return new MyClass(original);
  }
}

const obj = new MyClass;

obj.test = 1;
console.log(MyClass.import(obj.export()).test);
MyClass.import(obj.export()).test = 2;

try {
  window.postMessage(obj.export(), '*');
} catch(err) {
  console.error(err);
}
like image 165
Michał Perłakowski Avatar answered Oct 28 '22 03:10

Michał Perłakowski