Search code examples
javascriptcopycoffeescriptprototype-oriented

How do I copy an object and it's prototype chain without calling its constructor function?


How do I copy an object and it's prototype chain without calling its constructor function?

In other words, what would the function dup look like in the following example?

class Animal
  @sleep: -> console.log('sleep')
  wake: -> console.log('wake')
end
class Cat extends Animal
  constructor: ->
    super
    console.log('create')

  attack: ->
    console.log('attack')
end

cat = new Cat()         #> create
cat.constructor.sleep() #> sleep
cat.wake()              #> wake
cat.attack()            #> attack

dup = (obj) ->
  # what magic would give me an effective copy without
  # calling the Cat constructor function again.

cat2 = dup(cat)          #> nothing is printed!
cat2.constructor.sleep() #> sleep
cat2.wake()              #> wake
cat2.attack()            #> attack

As much as it pains me to look at, here's a jsfiddle of the example.

I'd also need the properties despite only using functions in my example.


Solution

  • function dup(o) {
        return Object.create(
            Object.getPrototypeOf(o),
            Object.getOwnPropertyDescriptors(o)
        );
    }
    

    Which relies on the ES6 Object.getOwnPropertyDescriptors. You can emulate it. Taken from pd

    function getOwnPropertyDescriptors(object) {
        var keys = Object.getOwnPropertyNames(object),
            returnObj = {};
    
        keys.forEach(getPropertyDescriptor);
    
        return returnObj;
    
        function getPropertyDescriptor(key) {
            var pd = Object.getOwnPropertyDescriptor(object, key);
            returnObj[key] = pd;
        }
    }
    Object.getOwnPropertyDescriptors = getOwnPropertyDescriptors;
    

    Live Example

    Converting this into coffeescript is left as an exercise for the user. Also note that dup shallow copies own properties.