3

I've been trying to understand inheritance in Javascript and so far I've read many sites about that (including javascript.info and Crockford's Javascript Good parts) - yet I can't seem to understand something as simple as Array inheritance.

Maybe if I demonstrate with an example, somebody can correct me and teach me what I'm getting wrong.

function ExtendedArray() {
    Array.call(this, arguments);

    this.test = function () {
        return 'something';
    }
}

//I think this is the most standard way to extend a class?
ExtendedArray.prototype = [];
ExtendedArray.prototype.constructor = ExtendedArray;

$scope = {};

$scope.arr = new Array(1, 2, 3);
$scope.concatArr = [].concat($scope.arr);

$scope.x = new ExtendedArray(1, 2, 3);    //empty | instanceof Array = true
$scope.concatX = [].concat($scope.x);     //empty

$scope.y = new ExtendedArray();          //instanceof Array = true
$scope.y.push(1, 2, 3);                  //works - elements are added!
$scope.concatY = [].concat($scope.y);    //concats it like a object

Here is a JS-Fiddle for the same:

http://jsfiddle.net/superasn/pq2j139c/

Some questions:

  1. How do I fix this code so that ExtendedArray behaves as Array?
  2. As you can see $scope.x is empty. Why is the constructor not working?
  3. The push functions works!? But then concat fails? How to make concat work?
  4. I see there are some libraries to extend Classes, is that a better approach to JS inheritance?

Your advise is appreciated!

supersan
  • 5,671
  • 3
  • 45
  • 64
  • 1
    `[].concat($scope.x)` is **not empty**, it contains one instance of an `ExtendedArray` object – CodingIntrigue Apr 30 '15 at 11:47
  • 2
    I just found [this article](http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/) from [this question](http://stackoverflow.com/questions/3261587/subclassing-javascript-arrays-typeerror-array-prototype-tostring-is-not-generi) - seems relevant – CodingIntrigue Apr 30 '15 at 11:51
  • Thanks.. Yes, i too found that perfectionkills article yesterday and it only added to my confusion. I stopped reading when things started getting into weird territory with him using Iframes for something as simple as array inheritance.. i'll give it another go today. – supersan Apr 30 '15 at 11:55
  • I'm not surprised, it is long-winded and non-trivial. You might want to just look at the [Naive Approach](http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/#naive_approach) which seems to be equivalent to what you're attempting to achieve – CodingIntrigue Apr 30 '15 at 11:56
  • You are right.. I modified my fiddle and it seems to be working.. http://jsfiddle.net/superasn/9ykr1gbn/ Now to fix the concat thing and understand inheritance better (p.s. sorry i shouldn't post so frequently but i'm pretty excited to see it working) – supersan Apr 30 '15 at 12:03

1 Answers1

0

You just must call [].push.apply(this, arguments); in constructor:

angular.module('myApp', [])
.controller('mainCtrl', ['$scope', function($scope) {

    var __extends = this.__extends || function (d, b) {
                for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
                function __() { this.constructor = d; }
                __.prototype = b.prototype;
                d.prototype = new __();
            };
    
    function ExtendedArray() {
        Array.call(this, arguments);
        
        [].push.apply(this, arguments);
        
        this.test = function () {
            return 'something';
        }
    }
    
    __extends(ExtendedArray, Array);

    $scope.arr = new Array(1, 2, 3);
    $scope.concatArr = [].concat($scope.arr);
    
    $scope.x = new ExtendedArray(1, 2, 3);    
    $scope.concatX = [].concat($scope.x);
    
    $scope.y = new ExtendedArray();    
    $scope.y.push(1, 2, 3);
    $scope.concatY = [].concat($scope.y);
    
    $scope.isArray = function(v) {
        return v instanceof Array;
    }
    
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="mainCtrl">
   <div class="content">
       Arr: Val = {{arr}} / Concat = {{concatArr}} / Is Array? {{isArray(arr)}}
       
       <hr/>

       X: Val = {{x}} / Concat = {{concatX}} / Is Array? {{isArray(x)}}

       <hr/>

       Y: Val = {{y}} / Concat = {{concatY}} / Is Array? {{isArray(y)}}
       
    </div>
</div>
  • thanks! part 1 is working! now two quick questions, what the use of calling `Array.call(this, arguments);` if we have to `push` the arguments. Secondly, concat is still not working. It still thinks of it as one item.. how do I make concat work the way it works on a normal array? – supersan Apr 30 '15 at 12:08
  • 2
    `Array.call(this, arguments);` is doing absolutely nothing. You should remove it. – Bergi Apr 30 '15 at 13:34