21

I came across an issue with a plugin that uses object.create in jquery to create a date dropdown. I just noticed in IE 8 that it is throwing an error of:

SCRIPT438: Object doesn't support property or method 'create'

Here is the code:

var dropdateobj = Object.create(dropdatefuncs);
dropdateobj.create(options, this);
$.data(this, 'dropdate', dropdateobj);

What is a good work around for IE8 or more cross browser compatible?

Thanks in advance!

klye_g
  • 1,242
  • 6
  • 31
  • 54

3 Answers3

37

If you need Object.create, there are good chances you may need to rely on other es5 features as well. Therefore, in most cases the appropriate solution would be to use es5-shim.

However, if Object.create is the only thing you need and you only use it to purely setup the prototype chain, here's a lightweight poly-fill that doesn't support null as the first argument and doesn't support the second properties argument.

Here's the spec:

15.2.3.5 Object.create ( O [, Properties] )

The create function creates a new object with a specified prototype. When the create function is called, the following steps are taken:

If Type(O) is not Object or Null throw a TypeError exception.

Let obj be the result of creating a new object as if by the expression new Object() where Object is the standard built-in constructor with that name

Set the [[Prototype]] internal property of obj to O.

If the argument Properties is present and not undefined, add own properties to obj as if by calling the standard built-in function Object.defineProperties with arguments obj and Properties.

Return obj.

Here's the lightweight implementation:

if (!Object.create) {
    Object.create = function(o, properties) {
        if (typeof o !== 'object' && typeof o !== 'function') throw new TypeError('Object prototype may only be an Object: ' + o);
        else if (o === null) throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");

        if (typeof properties != 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");

        function F() {}

        F.prototype = o;

        return new F();
    };
}
plalx
  • 42,889
  • 6
  • 74
  • 90
  • 2
    The second parameter is a joke, I wonder if someone actually uses that ridiculously verbose syntax to create objects in actual code – Esailija Aug 02 '13 at 15:13
  • @plalx: MDN is collaboratively-edited. There is no "official" one. I've seen some *seriously* flawed code on MDN. (Check out the first "compatibility" example on the [`Array#forEach` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach), for instance. Completely and utterly wrong.) See the implementation in [es5-shim](https://github.com/kriskowal/es5-shim/) for something that at least makes a best effort where it can. – T.J. Crowder Aug 02 '13 at 15:14
  • @Esailija: That ridiculously verbose syntax is currently the only syntax available for defining property descriptors. –  Aug 02 '13 at 15:14
  • @CrazyTrain defineProperty or defineProperties? – Esailija Aug 02 '13 at 15:15
  • 1
    @Esailija: those use the same syntax for property descriptors. –  Aug 02 '13 at 15:15
  • @CrazyTrain yes but when I use those I have very special situation where I actually need to alter descriptors. Not every-day normal object creating which Object.create second parameter attempts to be. – Esailija Aug 02 '13 at 15:16
  • Why would someone downvote this answer? It's *clearly* useful. – T.J. Crowder Aug 02 '13 at 15:17
  • @Esailija: Sure, but when you need it, you need it. The second argument to `Object.create` isn't required. I wouldn't see a benefit in passing a single argument to `Object.create` then subsequently invoking `Object.defineProperties` –  Aug 02 '13 at 15:17
  • @CrazyTrain If you put it that way - a very minor convenience - then I agree. So far I have never needed this convenience though because I use object.create just to link prototype chains. My original comment was about every-day object creating using object.create - nobody uses the second argument in that case but they use a initializer function. And so far I only know that Raynos does this. lol – Esailija Aug 02 '13 at 15:18
  • @Esailija: Well I do agree that the syntax is ridiculously verbose. AFAIK, that'll be remedied in ES6 with a literal syntax. –  Aug 02 '13 at 15:19
  • @T.J.Crowder, Well if the community have not changed the implementation, it's because it is widely accepted and works well in most cases, since people mostly use `Object.create` to setup the prototype chain only. I am not saying there aren't better implementations and this one should be used in all cases however. – plalx Aug 02 '13 at 15:23
  • Ugh, don't use this! Stop using this crappy polyfill. – Mulan Aug 02 '13 at 16:32
  • @naomik Then what would you suggest doing? (Please don't say "Upgrade your browser.") – krillgar Sep 16 '14 at 14:52
  • @naomik That polyfill is perfectly fine in most cases. Anyway, `Object.create` can't be shimmed perfectly so trying to use it for more advanced use cases than simply setting up the prototype chain is just asking for trouble... – plalx Sep 16 '14 at 15:40
20

There are several shims that provide this, including this one.

Note that Object.create can't be perfectly shimmed, though, because amongst other things it can create non-enumerable properties or properties with getters and setters, which you can't do on all pre-ES5 browsers. (You can do getters and setters on some pre-ES5 browsers using proprietary syntax, but not on IE8 I don't believe.) It can only be pseudo-shimmed.

But a pseudo-shim will do for the use-case you've quoted.

Just for completeness, here's a simple version of the part that can be shimmed:

if (!Object.create) {
    Object.create = function(proto, props) {
        if (typeof props !== "undefined") {
            throw "The multiple-argument version of Object.create is not provided by this browser and cannot be shimmed.";
        }
        function ctor() { }
        ctor.prototype = proto;
        return new ctor();
    };
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    This polyfill is much easier to read than the one proposed by plalx in the other answer although both do the trick. – Lorenzo Polidori Mar 06 '15 at 09:32
  • @plalx: Re efficiency: I bet you it's unmeasurable :-) -- and certainly not material in any real-world use case. I prefer the cleanliness of absolutely no link between the created objects. *"Also, directly throwing strings in my opinion is not very good as it breaks the error contract."* There is no error contract in JavaScript. But yea, `new Error` might be better on browsers that support it. – T.J. Crowder Mar 06 '15 at 14:07
  • 1
    @T.J.Crowder I think you are right about not leaving a link. I changed the posted implementation to behave closer to the spec while remaining as lightweight as possible. Also converted to a community wiki. – plalx Mar 06 '15 at 15:56
  • @plalx: It's really great you curate the accepted answer so well, nice one. What SO's all about. – T.J. Crowder Mar 06 '15 at 16:03
0

This will make Object.create() work in IE 8.

I tried the shim/sham but that didn't work for me.

if (typeof Object.create !== 'function') {
 Object.create = function(o, props) {
  function F() {}
  F.prototype = o;

  if (typeof(props) === "object") {
   for (prop in props) {
    if (props.hasOwnProperty((prop))) {
     F[prop] = props[prop];
    }
   }
  }
  return new F();
 };
}
Sorter
  • 9,704
  • 6
  • 64
  • 74