How best to inherit from native JavaScript object? (Especially String)

后端 未结 4 1989
北恋
北恋 2021-02-12 18:01

I\'m a long-time browser but a first time participator. If I\'m missing any etiquette details, please just let me know!

Also, I\'ve searched high and low, including this

相关标签:
4条回答
  • 2021-02-12 18:33

    I would look into creating a new object, using the native object as a backing field and manually recreating the functions for the native objects. For some very rough, untested sample code...

    var myString = {
        _value = ''
        ,substring:_value.substring
        ,indexOf:_value.indexOf
    }
    

    Now, I'm sure this wont work as intended. But I think with some tweaking, it could resemble on object inherited from String.

    0 讨论(0)
  • 2021-02-12 18:35

    The painfully simple but flawed way of doing this would be:

    var MyString = function() {};
    
    MyString.prototype = new String();
    

    What you're asking for is strange though because normally in JS, you aren't treating them as string objects, you're treating them as "string" types, as primitive values. Also, strings are not mutable at all. You can have any object act as though it were a string by specifying a .toString method:

    var obj = {};
    obj.toString = function() {
      return this.value;
    };
    obj.value = 'hello';
    
    console.log(obj + ' world!');
    

    But obviously it wouldn't have any string methods. You can do inheritence a few ways. One of them is the "original" method javascript was supposed to use, and which you and I posted above, or:

    var MyString = function() {};
    var fn = function() {};
    fn.prototype = String.prototype;
    MyString.prototype = new fn();
    

    This allows adding to a prototype chain without invoking a constructor.

    The ES5 way would be:

    MyString.prototype = Object.create(String.prototype, {
      constructor: { value: MyString }
    });
    

    The non-standard, but most convenient way is:

    MyString.prototype.__proto__ = String.prototype;
    

    So, finally, what you could do is this:

    var MyString = function(str) {
      this._value = str;
    };
    
    // non-standard, this is just an example
    MyString.prototype.__proto__ = String.prototype;
    
    MyString.prototype.toString = function() {
      return this._value;
    };
    

    The inherited string methods might work using that method, I'm not sure. I think they might because there's a toString method. It depends on how they're implemented internally by whatever particular JS engine. But they might not. You would have to simply define your own. Once again, what you're asking for is very strange.

    You could also try invoking the parent constructor directly:

    var MyString = function(str) {
      String.call(this, str);
    };
    
    MyString.prototype.__proto__ = String.prototype;
    

    But this is also slightly sketchy.

    Whatever you're trying to do with this probably isn't worth it. I'm betting there's a better way of going about whatever you're trying to use this for.

    If you want an absolutely reliable way of doing it:

    // warning, not backwardly compatible with non-ES5 engines
    
    var MyString = function(str) {
      this._value = str;
    };
    
    Object.getOwnPropertyNames(String.prototype).forEach(function(key) {
      var func = String.prototype[key];
      MyString.prototype[key] = function() {
        return func.apply(this._value, arguments);
      };
    });
    

    That will curry on this._value to every String method. It will be interesting because your string will be mutable, unlike real javascript strings.

    You could do this:

        return this._value = func.apply(this._value, arguments);
    

    Which would add an interesting dynamic. If you want it to return one of your strings instead of a native string:

        return new MyString(func.apply(this._value, arguments));
    

    Or simply:

        this._value = func.apply(this._value, arguments);
        return this;
    

    There's a few ways to tackle it depending on the behavior you want.

    Also, your string wont have length or indexes like javascript strings do, a way do solve this would be to put in the constructor:

    var MyString = function(str) {
      this._value = str;
      this.length = str.length;
      // very rough to instantiate
      for (var i = 0, l = str.length; i < l; i++) {
        this[i] = str[i];
      }
    };
    

    Very hacky. Depending on implementation, you might just be able to invoke the constructor there to add indexes and length. You could also use a getter for the length if you want to use ES5.

    Once again though, what you want to do here is not ideal by any means. It will be slow and unnecessary.

    0 讨论(0)
  • 2021-02-12 18:36

    You can't assign the this in a constructor

    this=n is an error

    Your myarray is just an alias for the native Array- any changes you make to myarray.prototype are changes to Array.prototype.

    0 讨论(0)
  • 2021-02-12 18:37

    This line is not valid:

    this = n;
    

    this is not a valid lvalue. Meaning, you cannot assign to the value referenced by this. Ever. It's just not valid javascript. Your example will work if you do:

    var myString = function (n){
        this.prop = n;
    
        this.a = function (){
            alert(this.prop);
        };
    }
    
    myString.prototype = new String; // or String.prototype;
    
    var x = new myString("foo");
    x.a();
    

    Regarding your workaround, you should realise that all you're doing is making a String object, augmenting a function property, and then calling it. There is no inheritance taking place.

    For example, if you execute x instanceof myString in my example above it evaluates to true, but in your example it isn't, because the function myString isn't a type, it's just a regular function.

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