Extend native JavaScript array

后端 未结 10 807
情书的邮戳
情书的邮戳 2020-11-27 22:08

Is there any way to inherit a class from JS native function?

For example, I have a JS function like this:

function Xarray()
{
    Array.apply(this, a         


        
相关标签:
10条回答
  • 2020-11-27 22:53

    In your case, a good bet would be to use this pattern:

    function XArray(array) {
      array = array || [];
    
      //add a new method
      array.second = function second() {
        return array[1];
      };
    
      //overwrite an existing method with a super type pattern
      var _push = array.push;
      array.push = function push() {
        _push.apply(array, arguments);
        console.log("pushed: ", arguments);
      };
    
      //The important line.
      return array
    }
    

    Then you can do:

    var list = XArray([3, 4]);
    list.second()   ; => 4
    
    list[1] = 5;
    list.second()   ; => 5
    

    note however that:

    list.constructor  ; => Array and not XArray
    
    0 讨论(0)
  • 2020-11-27 22:54

    Constructors that return an object implicitly substitute the value of this for callers of super(). Generated constructor code has to capture whatever super() returns and replace it with this.

    Built-in classes use ES6 new.target to do the fixup but there's no way for ES5 code to ensure that new.target has a value calling the constructor.

    This is why your extra methods vanish - your object has the wrong prototype.

    All you need to do is fix the prototype chain after calling super().

    export class RoleSet extends Array {
      constructor() {
        super();
        Object.setPrototypeOf(this, RoleSet.prototype);
      }
      private containsRoleset(roleset:RoleSet){
          if (this.length < roleset.length) return false;
          for (var i = 0; i < roleset.length; i++) {
            if (this.indexOf(roleset[i]) === -1) return false;
          }
          return true;
      }
      public contains(item: string | RoleSet): boolean {
        if (item) {
          return typeof item === "string" ? 
            this.indexOf(item) !== -1 : 
            this.containsRoleset(item);
        } else {
          return true;
        }
      }
    }
    

    Be aware that this curse shall afflict thy children and thy children's children until the end of code; you have to do the fixup in every generation of an inheritance chain.

    0 讨论(0)
  • 2020-11-27 22:54

    With purpose to overcome the problem of extension of the native Array class, I took advantage of a decorator.

    function extendArray(constructor: Function) {
        Object.getOwnPropertyNames(constructor.prototype)
            .filter(name => name !== 'constructor')
    .forEach(name => {
        const attributes = Object.getOwnPropertyDescriptor(constructor.prototype, name);
        Object.defineProperty(Array.prototype, name, attributes);
      });
    }
    
    @extendArray
    export class Collection<T> extends Array<T> {
      constructor(...args: T[]) {
        super(...args);
      }
      // my appended methods
    }

    BTW This decorator can be made more generic (for other native classes) if to use a decorator factory.

    0 讨论(0)
  • 2020-11-27 22:57

    Don't know how frowned upon this is but for example I needed to create an array of BulletTypes so that I could cycle through them. What I did is the following:

    interface BulletTypesArray extends Array<BulletType> {
        DefaultBullet?: Bullet; 
    }
    
    var BulletTypes: BulletTypesArray = [ GreenBullet, RedBullet ];
    BulletTypes.DefaultBullet = GreenBullet;
    

    Obviously you could could also make a generic interface, something like interface SuperArray<T> extends Array<T>.

    0 讨论(0)
提交回复
热议问题