Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object.getPrototypeOf #6

Closed
Raynos opened this issue Jul 21, 2011 · 12 comments
Closed

Object.getPrototypeOf #6

Raynos opened this issue Jul 21, 2011 · 12 comments

Comments

@Raynos
Copy link

Raynos commented Jul 21, 2011

See shim :

http://forrst.com/posts/Object_getPrototypeOf_shim-eNB

It might be worthwhile to add this to augment.

@olivernn
Copy link
Owner

That looks interesting, I tried to get a shim for this before based on John Resig's blog post but couldn't get it to work cross browser, this version looks a little more robust however, thanks for pointing it out.

@olivernn
Copy link
Owner

I've taken a closer look at this version of the shim and I'm not sure it can ever reliably work in IE. Because it eventually fallsback to checking constructor.prototype the shim will return different things based on how the prototype object was defined.

For example if the prototype is defined without an object literal the result is as expected:

Foo = function () {}
Foo.prototype.bar = "BAZ"
foo = new Foo ()

foo.constructor.prototype.bar // => "BAZ"

However if the prototype is defined using an object literal the constructor prototype points to Object.prototype

Foo = function () {}
Foo.prototype = {
  bar: "BAZ"
}
foo = new Foo ()

foo.constructor.prototype.bar // does not return "BAZ"

I have set up a little test that demonstrates this here.

If this is correct then I'm not sure it is a good idea to include the shim as part of augment, ideally all shims should behave very closely to the native implementations. Otherwise you will get different behaviour for the same methods depending on which browser they run in.

I'm more than willing to be proved wrong however, if you can see a way to make this behave as expected I'd be very happy to include it as part of augment.

@ELLIOTTCABLE
Copy link

This is a generally-known problem (regarding the difference-in-operation on I.E. versus, well, the rest of the world); how about instead exposing a cross-browser-consistent version of the I.E. functionality called getConstructorPrototypeOf, that will operate identically to getPrototypeOf in well-behaved code (i.e. code that maintains the constructor.prototype.constructor relationship), but at least operate predictably and consistently even on non-well-behaved code, in I.E. and elsewhere?

@olivernn
Copy link
Owner

Thats an interesting approach to the problem. I don't think there is anyway to implement Object.getPrototypeOf in JavaScript in a cross browser way. I'm not sure however that adding non-standard methods to augment is the correct way to solve this problem.

I think your getConstructorPrototypeOf might be more suited to supplement.js and I'd be more than happy to accept a patch to add it there. I feel that augment.js should only contain standard methods and only where they can be reliably implemented in JavaScript.

@ELLIOTTCABLE
Copy link

I’d agree, except that this is something that is “reliably implementable” everywhere except out-of-date IEs. In my opinion, out-of-date IEs “don’t matter,” beyond minimum efforts to make things work even to some minimal extent. Any sysadmin forcing an ancient IE upon their users is basically signing them up for the Shitty Web™, so there’s not a lot of point in wasting time/effort on it, or making a product of a lower quality overall just to pander to them.

… all that said, you, as the maintainer of this project, may disagree. ;D

@Raynos
Copy link
Author

Raynos commented Nov 14, 2011

Object.getPrototypeOf

is a simple return this.__proto__ in all non-IE browsers.

In IE browsers it's a simple return this.constructor.prototype

The only case it breaks if people use new Constr but forget to set Constr.prototype.constructor and then that's basically saying if you write bad code the method breaks.

The solution is warning people not to write bad code rather then not giving people a method that works.

@olivernn
Copy link
Owner

@ELLIOTTCABLE - the main reason to use augment.js is to be able to seamlessly use the more modern JavaScript methods in old browsers such as IE. TBH if you are not supporting IE less than 8 you probably aren't getting a huge amount of benefit from augment.js since the browser share of old versions of safari, firefox etc are quite small.

@Raynos - if the Constr.prototype.constructor has been set then yes this does work. I must have been writing some bad code for quite a while now though as I don't think I've ever actually set that in my own code!

Perhaps this method could be added, with the caveat that you must set the constructor property in your prototype in IE if you are defining a prototype using an object literal. I guess without augment.js you would have to do this anyway to get similar behaviour.

Ideally I would like to be able to throw some kind of error in IE if Constr.prototype.constructor has not been set, just so that you are forced to do this if you want to use this method in IE.

I'll try and put something together this week, I'd appreciate any feedback on the implementation once its done.

@ELLIOTTCABLE
Copy link

@olivernn that’s entirely my point. This only doesn’t work in the case of writing_bad_code LOGICAL AND developing_for_IE, and IMO, there’s so little of an excuse for the entirety of the set union applying to those situations, that it’s entirely includable.

Not a big deal either way, I suppose. ^_^

@olivernn
Copy link
Owner

Okay this is what I have so far, this does work in IE.

;(function () { "use strict"

  var ensureIsObject = function (param) {
    if (param !== Object(param)) throw new TypeError('Object.getPrototypeOf called on non-object');
  }

  if (!Object.getPrototypeOf) {
    if (typeof "test".__proto__ === "object") {
      Object.getPrototypeOf = function (obj) {
        ensureIsObject(obj)
        return obj.__proto__
      }
    } else {
      Object.getPrototypeOf = function (obj) {
        ensureIsObject(obj)
        return obj.constructor.prototype
      }
    };
  };
})();

I'm toying with the idea of adding a check to the IE version that throws a warning if you are setting the prototype using an object literal but haven't set the constructor property. So far though the only way I can see to do this is something like this:

    ({}).constructor.prototype === obj.constructor.prototype

The problem with this would be if you were calling Object.getPrototypeOf on a plain object. I'm not entirely sure why you would be doing this, but if you did want to, throwing an error here would mean you were screwed. Perhaps this check is unnecessary though, thoughts?

@ELLIOTTCABLE
Copy link

… that test is already incorrect, right off the bat, isn’t it? As (new new Function()()).constructor.prototype !== Object.prototype. When you create a new function, a new prototype object is immediately created for it, is it not? Thus, there’s no real way to determine if <something>.constructor’s .prototype was changed after new <something>.constructor() resulted in the construction. At least, that I can think of off the top of my head.

@olivernn
Copy link
Owner

Yeah good catch - was just hoping that there was a way to catch the case where the prototype was assigned to an object literal but constructor hadn't been set. TBH trying to catch it will probably cause more problems then it would solve.

I'll try and put together a release sometime this week with Object.getPrototypeOf included. There are a couple of other build related things I'd like to clean up as well though so it could be a couple of days.

@olivernn
Copy link
Owner

I've just released version 0.4.0 of augment that includes the discussed implementation of Object.getPrototypeOf.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants