سؤال

I'm working on an AngularJS SPA and I'm using prototypes in order to add behavior to objects that are incoming through AJAX as JSON. Let's say I just got a timetable x from an AJAX call.

I've defined Timetable.prototype.SomeMethod = function() and I use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf in order to set the prototype of x to TimeTable.prototype. I have the polyfill in place too.

If I call x.SomeMethod() this works in IE > 9, FF, Chrome etc. However, IE 9 gives me a headache and says throws an error stating 'x does not have property or member SomeMethod'.

Debugging in IE shows me that the _proto_ of x has SomeMethod() in the list of functions, however, calling x.SomeMethod() gives the same error as described.

How can I make this work in IE9 ?

هل كانت مفيدة؟

المحلول 2

This is how I solved it at the end:

Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
    if (!isIE9()) {
        obj.__proto__ = proto;
    } else {
        /** IE9 fix - copy object methods from the protype to the new object **/
        for (var prop in proto) {
            obj[prop] = proto[prop];
        }
    }

    return obj;
};

var isIE9 = function() {
    return navigator.appVersion.indexOf("MSIE 9") > 0;
};

نصائح أخرى

More comment than answer

The main problem with "extending" a random object retrieved from some other environment is that javascript doesn't really allow random property names, e.g. the random object may have a property name that shadows an inherited property. You might consider the following.

Use the random object purely as data and pass it to methods that access the data and do what you want, e.g.

function getName(obj) {
    return obj.name;
}

So when calling methods you pass the object to a function that acts on the object and you are free to add and modify properties directly on the object.

Another is to create an instance with the methods you want and copy the object's properties to it, but then you still have the issue of not allowing random property names. But that can be mitigated by using names for inherited properties that are unlikely to clash, e.g. prefixed with _ or __ (which is a bit ugly), or use a naming convention like getSomething, setSomething, calcLength and so on.

So if obj represents data for a person, you might do:

// Setup
function Person(obj){
  for (var p in obj) {
    if (obj.hasOwnProperty(p)) {
      this[p] = obj[p];
    } 
  }
}

Person.prototype.getName = function(){
  return this.name;
};

// Object generated from JSON
var dataFred = {name:'fred'};

// Create a new Person based on data
var p = new Person(dataFred);

You might even use the data object to create instances from various consructors, e.g. a data object might represent multiple people, or a person and their address, which might create two related objects.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top