Anybody know how to do a deep copy/cloning of a native javascript event object? I know I can create a new event object and set the appropriate properties manually to match the original event, but it'd be much easier if there's a way to just clone.
-
I should have also pointed out, you can pretty much do anything to the event object you want after you get a hold of it without blowing anything up if that was your concern. It's just a simple object built and passed into a handler from native code and doesn't have any dependencies. In <= IE8's case window.event is just a shelf for event objects that has objects swapped out whenever a new event is handled. If you reference the window.event object elsewhere in old IE, you should hold on to the original object when window.event gets replaced assuming it's a typical object reference. – Erik Reppen Sep 26 '12 at 16:45
-
1related: https://stackoverflow.com/q/12752818/104380 – vsync Dec 18 '19 at 11:18
-
related: https://stackoverflow.com/q/35215015/104380 – vsync Dec 18 '19 at 11:31
-
**Don't use the below, use `new MouseEvent()` as described in the answer linked above, which is this one: https://stackoverflow.com/a/32670713/1599699** – Andrew May 25 '20 at 19:32
-
^ **Note** that there's also `WheelEvent`, for scrolling, and `MouseEvent` won't function properly for that: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent – Andrew May 30 '20 at 01:49
4 Answers
Above code will not copy any getters/setters properly. Try:
function cloneEvent(e) {
if (e===undefined || e===null) return undefined;
function ClonedEvent() {};
let clone=new ClonedEvent();
for (let p in e) {
let d=Object.getOwnPropertyDescriptor(e, p);
if (d && (d.get || d.set)) Object.defineProperty(clone, p, d); else clone[p] = e[p];
}
Object.setPrototypeOf(clone, e);
return clone;
}

- 17,260
- 17
- 99
- 173
For your purposes I'd just make it a prototype of a new object constructor and override the ones you want changed. Cloning in JS gets messy due to the circular reference issue so it may not be the quick and dirty solution you were hoping for.
function cloneEventObj(eventObj, overrideObj){
if(!overrideObj){ overrideObj = {}; }
function EventCloneFactory(overProps){
for(var x in overProps){
this[x] = overProps[x];
}
}
EventCloneFactory.prototype = eventObj;
return new EventCloneFactory(overrideObj);
}
//So add your override properties via an object
$el.click(function(e){
var newEventObj = cloneEventObj(
e,
{ target:document.body }
);
doSomething(newEventObj);
});
//or just stick 'em on manually after spitting the object out
/*...
var newEventObj = cloneEventObj(e);
newEventObj.target = document.body
...*/
In this case the 'cloned' object is the prototype object of the new object. 'this.' properties are checked for before the prototype object so these will override. Or you could just attach properties after the object is built.

- 4,605
- 1
- 22
- 26
-
1+2: In all my years JS programming, I never considered or heard of anyone using this awesome technique. No only is it simple, it's efficient! – Thomas Eding Sep 24 '12 at 22:37
-
Thanks! The prototype object is rarely explained well, IMO. It's just a back-up object that your instances refer to if something tries to reference a property that's not actually on the instance. If one isn't found at the prototype object check phase, that object's constructor's prototype object is checked and so on. – Erik Reppen Sep 24 '12 at 22:49
-
+1 Very eloquent solution.. due to the way instanceof works you'll even be able to use `clonedEvent instanceof Event`... just don't go cloning a clone of a clone of a clone ;) – Pebbl Sep 26 '12 at 00:49
-
Can anyone tell me a quick use-case for when cloning an event would come in handy? I understand about use-cases for event bubbling and capturing, but I've never been able to figure out when cloning an event would be necessary. – CodeOwl Oct 30 '13 at 21:02
-
@CodeOwl Event object info might trigger other forms of async behavior that you'd want to be able to queue so triggers happened in order. In IE<=8 the event object is just the global window.event which gets overwritten over and over again. Not sure if old references would point at the old event object or not. Depends on how it's created I suspect. – Erik Reppen Oct 30 '13 at 21:05
-
In the case of IE<=8 (and possibly higher), wouldn't this fail due to the property values of the clone's prototype changing? The event object has no own properties in this case. – NetMage Jul 09 '14 at 19:45
-
@NetMage Think of window.event as more of a pointer to the last thing the browser pointed at before you assigned it to a garbage-collection locking function in some event-handler assignment.. JS objects and closure refs generally stay alive until there is no longer anything referencing them. If you assign window.event to something it will stick around until you're done with that reference even if window.event gives you something else the second some other DOM event was triggered. – Erik Reppen Jul 23 '14 at 05:10
-
IE <=8 only ever has one event object - it doesn't create new objects for new events. Again, window.event has no own properties. – NetMage Jul 25 '14 at 17:40
-
In JS, Objects values are actually just by-value passed fancy pointers to the object and only get garbage collected when there are no longer references to them. For example: `var x = { whatsThatYouSay:"I still live" }; var y = x; x = { whatsThatYouSay:"hesNotReallyDeadJim" }; alert(x.whatsThatYouSay); alert(y.whatsThatYouSay);` – Erik Reppen Jul 28 '14 at 15:23
-
4This doesn't work in Chrome with properties that are read only: `function Event() {} Event.prototype = event; var ev = new Event(); console.log(ev.currentTarget);` yields "TypeError: Illegal invocation". These properties must be accessed directly on the original event object. – Jakub Vrána Nov 22 '17 at 12:15
-
1
Option 1: Making a new event with modification
You could make an Object.assign
-alike using proxies and construct a new event without modifying the original event
Example:
function EventModifier (evt, obj) {
const proxy = new Proxy(evt, {
get: (target, prop) => obj[prop] || target[prop]
})
return new evt.constructor(evt.type, proxy)
}
onclick = evt => {
evt = new EventModifier(evt, { altKey: true })
// Dispatch the new event on something else
console.log('clicked with alt key:', evt.altKey) // always true
}
This way you will use the same options as the original event that includes bubble, cancelable, key modifier, etc (doe it don't include any target as you are meant to dispatch the modified event on something else)
Option 2: Define new properties
Keeping the original event but override a key using Object.defineProperty
you could use defineProperties if you want to add more than just one.
onclick = evt => {
Object.defineProperty(evt, 'target', { value: document.querySelector('script') })
console.log('target:', evt.target)
}

- 34,080
- 13
- 108
- 131
Inspired by Kofifus answer I just do that
function cloneEvent(type, event) {
var evt = new Event(type);
return Object.setPrototypeOf(evt,event);
}
or just
function cloneEvent(event){
return Object.create(event)
}
it returns a new object that protects you from edit the original object. but let you read and edit the property. thanks to js prototype chain
Newest js engine support 'structuredClone' that should do it for you

- 7,713
- 6
- 52
- 57