What modernizer scripts exist for the new ECMAScript 5 functions?

前端 未结 4 1433
伪装坚强ぢ
伪装坚强ぢ 2020-12-08 11:54

ECMAScript 5 has quite a few nice additions. John Resig has a good overview here. Here is a good ECMAScript 5 compatibility table.

A lot of this stuff can be \"fake

4条回答
  •  感动是毒
    2020-12-08 12:31

    Crockford recommends this kind of Object.create shim:

    if (typeof Object.create != "function") {
      Object.create = function (o) {
        function F(){}
        F.prototype = o;
        return new F;
      };
    }
    

    But please don't do this.

    The problem with this approach is that ES5 Object.create has a signature of 2 arguments: first — an object to inherit from, and second (optional) — an object representing properties (or rather, descriptors) to add to newly created object.

    Object.create(O[, Properties]); // see 15.2.3.5, ECMA-262 5th ed.
    

    What we have is an inconsistent implementation with 2 different behaviors. In environments with native Object.create, method knows how to handle second argument; in environments without native Object.create, it doesn't.

    What are the practical implications?

    Well, if there's some code (say, a third party script) that wants to use Object.create, it's rather reasonable for that code to do this:

    if (Object.create) {
      var child = Object.create(parent, properties);
    }
    

    — essentially assuming that if Object.create exists, it must conform to specs — accept second argument and add corresponding properties to an object.

    But, with the above-mentioned shim, second argument is simply ignored. There's not even an indication of something going wrong differently. A silent failure, so to speak — something that's rather painful to detect and fix.

    Can we do better?

    Well, it's actually impossible to create a fully-conforming Object.create shim using only (standard) ES3 facilities. The best solution is to create a custom wrapper method.

    There are, however, few alternative (less than optimal) things you can try:

    1) Notify user about inability to work with second argument

    if (!Object.create) {
      Object.create = function (o) {
        if (arguments.length > 1) { 
          throw Error('second argument is not supported'); 
        }
        // ... proceed ...
      };
    }
    

    2) Try to handle second argument:

    if (!Object.create) {
      Object.create = function (parent, properties) {
        function F(){}
        F.prototype = parent;
        var obj = new F;
        if (properties) {
          // ... augment obj ...
        }
        return obj;
      }; 
    }
    

    Note that "properties" is an object representing property descriptors, not just property names/values, and is something that's not very trivial to support (some things are not even possible, such as controlling enumerability of a property):

    Object.create(parent, {
      foo: {
        value: 'bar',
        writable: true
      },
      baz: {
        get: function(){ return 'baz getter'; },
        set: function(value){ return 'baz setter'; },
        enumerable: true
      }
    });
    

    The other inconsistency in the original shim is that it doesn't take care of parent object being null.

    var foo = Object.create(null);
    

    This creates an object whose [[Prototype]] is null; in other words, object that doesn't inherit from anything, not even Object.prototype (which all native objects in ECMAScript inherit from).

    foo.toString; // undefined
    foo.constructor; // undefined
    // etc.
    

    This is, by the way, useful to create "proper" hash tables in ECMAScript.

    It's possible to emulate this behavior, but only using non-standard extensions, such as "magical" __proto__ property (so implementation would be not very portable or robust). Solution to this problem is similar: either emulate ES5 implementation fully, or notify about inconsistency/failure.

提交回复
热议问题