2

In JavaScript there's a pattern to achieve inheritance called "Functional inheritance" described in chapter 5 of Crockfords "JavaScript: the good parts".

One of the disadvantages of the pattern -- as compared to using the pseudo-classical pattern -- is that we lose the ability to distinguish types using the instanceof operator.

Is there any way to achieve the same goal? How can we know that two objects are somehow related because they are of the same parent/base "type"?

Also how can we tell even though they are descendants of the same type they are different types themselves?

I don't know if not being able to use instanceof is a big loss but it doesn't seem like it is.

Notes

For those who are not familiar with Crockford's explanation, you can see an example at: JSFiddle, taken from here.

Sebastien Daniel
  • 4,649
  • 3
  • 19
  • 34
pgpb.padilla
  • 2,318
  • 2
  • 20
  • 44
  • 1
    Not everybody has read that book. Please explain what that "Functional inheritance" is, exactly. In which way do you "lose the ability to distinguish types using the instanceof operator"? – Oriol Feb 14 '16 at 18:47

4 Answers4

1

So imagine we have these:

mammal { giveBirth }
reptile { layEgg }
cat : mammal { purr, playWithChildren }
dog : mammal { bark }
lion : mammal { purr }

(cat inherits mammal and implements purr() etc...)

Now imagine you have an array of animals.

What I think you're asking is how do we tell if animals[0] is a cat.

The desire to know if animals[0] is a cat comes from the fact we know that cats can do certain things. Instead of knowing if animals[0] is a cat what we really want to know is can animals[0] purr. Perhaps animals[0].purr !== undefined is more accurate than knowing if it is a cat. This does mean that we need to check for each of the functions rather than the container concept of a cat which we know implements several functions but it makes the implementation more robust and future proof (consider if we only cared about purring and lions were added to the types of animals later).

As for the question about inheritance again I would suggest that we don't need to know if the animal is a mammal we need to know if they giveBirth. This would again ensure that our implementation is more future proof so that when we add marsupial later all of our logic around giving birth rather than laying an egg still stands.

Ed'
  • 397
  • 2
  • 7
1

The instanceof operator is not special. You can implement it yourself as explained on the Mozilla Developer Network. See the accepted answer to the following question for more details:

JavaScript inheritance and the constructor property

Here's how the instanceof operator can be implemented in JavaScript:

function instanceOf(object, constructor) {
    while (object != null) {
        if (object == constructor.prototype) { //object is instanceof constructor
            return true;
        } else if (typeof object == 'xml') { //workaround for XML objects
            return constructor.prototype == XML.prototype;
        }
        object = object.__proto__; //traverse the prototype chain
    }
    return false; //object is not instanceof constructor
}

Want to implement instanceOf for functional inheritance? That's easy to do too:

var object = child({ name: "a functional object" });

alert(object.instanceOf(child)); // true
alert(object.instanceOf(base));  // true
alert(object.sayHello());        // Hello, I'm a functional object

function base(spec) {
    var that = {};
    that.name = spec.name;
    that.constructors = [base];
    that.instanceOf = instanceOf;
    return that;
}

function child(spec) {
    var that = base(spec);
    that.sayHello = sayHello;
    that.constructors.push(child);
    return that;

    function sayHello() {
        return "Hello, I'm " + this.name;
    }
}

function instanceOf(constructor) {
     return this.constructors.indexOf(constructor) >= 0;
}

Of course, in real functional programming there's no need to use instanceof at all.

Community
  • 1
  • 1
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • Can you elaborate on why there's no need for `instanceof` in functional programming? I know there are typed and untyped implementations. Is there a reason we would never need to know the type of a variable? – pgpb.padilla Feb 20 '16 at 19:48
  • @pgpb.padilla The `instanceof` operator inspects the type of a value at runtime, allowing you to do different things based on the type of the value. In functional programming a [sum type](https://en.wikipedia.org/wiki/Tagged_union) is used for the same purpose. However, it is checked at compile time instead of runtime. For example, if you want to write a function that does different things depending on whether you give it a `Cat` or a `Dog` then the type of the argument would be `Either Cat Dog` and it's values would be `Left someCat` or `Right someDog`. Does that make sense? Hope that helps. – Aadit M Shah Feb 20 '16 at 20:17
  • I really don't know much about Haskell or sum types but [Ben's](http://stackoverflow.com/users/450128/ben) comment on [this question](http://stackoverflow.com/q/29284765/400544) makes sense to me. Basically he said that the whole point of having polymorphism is to have Cat and Dog treated in exactly the same way so having to check their types would be missing the point. – pgpb.padilla Feb 21 '16 at 04:59
0

Store a parent object in the object, then

if (obj1.parentObject == obj2.parentObject) {//Do your things}
Bálint
  • 4,009
  • 2
  • 16
  • 27
  • Take a look at the fiddle link, this approach would not work since the references to the parents are different. The parent is just a parent in the sense that it represents the same type, not necessarily that it is the same object. – pgpb.padilla Feb 14 '16 at 19:04
0

There are no certain types and distinction though inctanceof in "Functional inheritance"("JavaScript: the good parts").
It's about an exchange and relation between anonymous functions, which are generating objects, usually, with a private functionality.
The logical hierarchy of those function is set with conditional preference.
That functions can call each other, extend "parent" object methods, expand its functionality.
For example, in "functional inheritance" creating a new type, which is called "Mammal", would look like:

var mammal = function (spec) { 
    var that = {}; 
    that.get_.name = function () { 
    return spec.name; 
    }; 
    that.says = function () { 
    return spec.saying || ''; 
    }; 
    return that; 
}; 
var myMammal = mammal({name: 'Herb'});

By some conditional agreements we can accept it as a parent type(class).
Now we can create another anonymous function that will be responsible for subtype(subclass) of "Mammal" type(class). This function will call "parent" function mammal() to get the object with basic functionality:

var cat = function (spec) { 
    spec.saying = spec.saying || 'meow'; 
    var that = mammal(spec); 
    that.purr = function (n) { 
        var i, s = ''; 
        for (i = 9; i < n; i += 1) { 
            if (s) { 
               s += 
            } 
            s += 'r'; 
        } 
        return s; 
    }; 
    that.get_name = function () { 
        return that.says() + ' ' + spec.name + ' ' + that.says(); 
    }; 
    return that; 
}; 
var myCat = cat({name: 'Henrietta'}); 
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
  • I don't know how this explanation addresses the question, do you mean to say that the question posed incorrectly? If so please elaborate. – pgpb.padilla Feb 14 '16 at 21:34
  • Yes, that's how "functional inheritance" works, but how does this answer the question "*How to distinguish between the types?*" – Bergi Feb 14 '16 at 21:35
  • I've arrived at the notion, that there is no univocal alternative of `instanceof` and pseudo-types distinguishing in "functional inheritance". There is always will be different realizations and conditions of relations – RomanPerekhrest Feb 14 '16 at 21:51