Skip to the code
cf.

Object.create

Write Object.myCreate(proto, properties), which works like Object.create without calling it. It returns a new object whose prototype is proto.

proto must be an object or null. With null, the new object has no prototype at all, so it doesn't even have toString. Anything else (a number, a string, undefined) throws a TypeError.

properties is optional. When it's given, it maps property names to descriptors, in the format Object.defineProperties takes; define those properties on the new object. As with defineProperties, a flag you leave out (enumerable, writable, configurable) is false.

const animal = {
  speak() {
    return this.name + " makes a sound";
  },
};
const dog = Object.myCreate(animal, {
  name: { value: "Rex", enumerable: true },
});
dog.speak();                           // "Rex makes a sound"
Object.getPrototypeOf(dog) === animal; // true
Object.myCreate(null).toString;        // undefined

What the tests check

  1. returns an empty object whose prototype is proto
    const animal = { speak() { return "..."; } };
    const dog = Object.myCreate(animal);
    expect(Object.getPrototypeOf(dog)).toBe(animal);
    expect(dog.speak()).toBe("...");
    expect(Object.keys(dog)).toEqual([]);
    
  2. creates an object with no prototype from null
    const dictionary = Object.myCreate(null);
    expect(Object.getPrototypeOf(dictionary)).toBeNull();
    expect("toString" in dictionary).toBe(false);
    
  3. returns a new object on every call
    const proto = {};
    const first = Object.myCreate(proto);
    const second = Object.myCreate(proto);
    expect(first).not.toBe(second);
    expect(first).not.toBe(proto);
    
  4. throws a TypeError when proto isn't an object or null
    expect(() => Object.myCreate(42)).toThrow(TypeError);
    expect(() => Object.myCreate("proto")).toThrow(TypeError);
    expect(() => Object.myCreate(undefined)).toThrow(TypeError);
    
  5. defines properties from descriptors, with missing flags false
    const point = Object.myCreate({}, {
      x: { value: 1, enumerable: true },
      y: { value: 2 },
    });
    expect(point.x).toBe(1);
    expect(point.y).toBe(2);
    expect(Object.keys(point)).toEqual(["x"]);
    expect(Object.getOwnPropertyDescriptor(point, "y")).toEqual({
      value: 2,
      writable: false,
      enumerable: false,
      configurable: false,
    });
    
  6. works without the built-in Object.create
    const builtIn = Object.create;
    Object.create = function () {
      throw new Error("myCreate called the built-in Object.create");
    };
    let made;
    let bare;
    const proto = { kind: "proto" };
    try {
      made = Object.myCreate(proto);
      bare = Object.myCreate(null);
    } finally {
      Object.create = builtIn;
    }
    expect(Object.getPrototypeOf(made)).toBe(proto);
    expect(Object.getPrototypeOf(bare)).toBeNull();
    

Learn more

solution.jsSaved in this browser

Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.

Ctrl + Enter runs the tests (⌘ + Enter on a Mac).