Example of Javascript Duck Typing?

前端 未结 3 1622
無奈伤痛
無奈伤痛 2020-12-13 02:48

Some programmers advise against using pseudo classical inheritance in Javascript, but advise using duck-typing and giving each object a set of capabilities.

Is there

3条回答
  •  轮回少年
    2020-12-13 03:28

    Functions in JavaScript are versatile. They can be used as subroutines, methods, constructors, namespaces, modules, and much more.

    The reason people advise against using pseudo classical inheritance in JavaScript is because it hides the true power of JavaScript. Functions are just as expressive if not more expressive than objects. This has been proven by Alonzo Church who's work, Lambda Calculus, is Turing Complete.

    To answer your question directly I'll use functions to create a Turtle, a Lion and a Dolphin. Then I'll demonstrate how a turtle is an OceanAnimal and a LandAnimal, how a lion is only a LandAnimal, and how a dolphin is only an OceanAnimal. I'll conclude by explaining what is duck typing.

    First let's create the constructor for an OceanAnimal:

    function OceanAnimal() {
        this.swim = function (n) {
            return "I am " + this.name + ", the " + this.type +
                   ", and I just swam " + n + " meters.";
        };
    }
    

    Next we'll create the constructor for a LandAnimal:

    function LandAnimal() {
        this.walk = function (n) {
            return "I am " + this.name + ", the " + this.type +
                   ", and I just walked " + n + " meters.";
        };
    }
    

    Alright. So now let's create the constructor for a Turtle:

    Turtle.prototype.type = "turtle";
    
    function Turtle(name) {
        this.name = name;
        LandAnimal.call(this);
        OceanAnimal.call(this);
    }
    

    What's happening here? Okay, we want Turtle to inherit from both OceanAnimal and LandAnimal. So we're calling LandAnimal.call(this) and OceanAnimal.call(this). In this way we're using the OceanAnimal and LandAnimal constructors as mixins. Thus Turtle inherits from both OceanAnimal and LandAnimal without actually becoming of type OceanAnimal or LandAnimal.

    Another thing to notice is that we're setting the type property on the prototype of Turtle instead of inside it. This is because type is the same for all turtles. Thus it's shared. The name of each turtle on the other hand may vary and hence it's set inside the constructor.

    Now let's similarly create the constructor for a Lion:

    Lion.prototype.type = "lion";
    
    function Lion(name) {
        this.name = name;
        LandAnimal.call(this);
    }
    

    Since Lion is a LandAnimal we only mix in the LandAnimal constructor.

    Similarly for a Dolphin:

    Dolphin.prototype.type = "dolphin";
    
    function Dolphin(name) {
        this.name = name;
        OceanAnimal.call(this);
    }
    

    Now that we have created all the constructors let's create a turtle, a lion and a dolphin:

    var yoyo = new Turtle("Yoyo");
    var simba = new Lion("Simba");
    var dolphy = new Dolphin("Dolphy");
    

    Awww, now let's set them free:

    alert(yoyo.walk(10));
    alert(yoyo.swim(30));   // turtles are faster in the water
    alert(simba.walk(20));
    alert(dolphy.swim(20));
    

    Haha. That was fun. Personally I love yoyo the most.

    Okay, so what's duck typing? We know that yoyo is an OceanAnimal and a LandAnimal. However if we do yoyo instanceof OceanAnimal or yoyo instanceof LandAnimal then it returns false. What?

    • You: Stupid JavaScript. A Turtle is an OceanAnimal and a LandAnimal!
    • JavaScript: Not from where I'm standing. All I know is that it's a Turtle.
    • You: But if it swims then it's an OceanAnimal, and if it walks then it's a LandAnimal.

    So since JavaScript is such a party pooper we'll have to create our own test to check if an object is an OceanAnimal and if it's a LandAnimal.

    Let's start with an OceanAnimal:

    function isOceanAnimal(object) {
        if (typeof object !== "object") return false;
        if (typeof object.swim !== "function") return false;
        return true;
    }
    

    Similarly, for a LandAnimal:

    function isLandAnimal(object) {
        if (typeof object !== "object") return false;
        if (typeof object.walk !== "function") return false;
        return true;
    }
    

    So now we can use isOceanAnimal(yoyo) instead of yoyo instanceof OceanAnimal, and isLandAnimal(yoyo) instead of yoyo instanceof LandAnimal; and both these functions will return true for our beloved yoyo. Yay!

    This is a simple example of duck typing in JavaScript. To conclude:

    When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.

    Similarly:

    When I see an animal which swims like an ocean animal, I call that animal an ocean animal; and when I see an animal which walks like a land animal, I call that animal a land animal.

    Edit: You can see the above code in action here: http://jsfiddle.net/aaditmshah/X9M4G/

提交回复
热议问题