简体   繁体   中英

JavaScript pattern: “copy” ClassA properties to ClassB

seen this JavaScript pattern in some large projects, which "copies" or "implements" ClassA's properties to ClassB, but couldn't figure out what is the purpose of calling ClassA's empty constructor inside ClassB's constructor using ".call()" while passing the ClassB instance as "this" binding?

var ClassA = function() {
    //this function is totally empty
};

ClassA.prototype = {
    jump: function() {...some code...},
    dance: function() {
        if (this.canDance) {
            alert("dance");
        }
    }
};

ClassA.implementOn = function(targetClassOrObject) {
    for ( var prop in ClassA.prototype ) {      
        targetClassOrObject[ prop ] = ClassA.prototype[ prop ];
    }
};

var ClassB = function() {
    this.canDance = true;
    ClassA.call(this);          // <------------What's the purpose of this line?
};

ClassA.implementOn(ClassB.prototype);

var instanceOfB = new ClassB();
instanceOfB.dance();

If the ClassA constructor is empty, there's no big surprise here -- call ing ClassA 's empty constructor does absolutely nothing.

The moment you decide you want ClassA 's constructor to be non-empty, however, you'll see that line now has a tremendously important effect: constructing a ClassB object also invokes the ClassA -specific constructor behaviors in the context of newly-constructed ClassB object, which is what you'd expect if ClassB is a logical "subclass" of ClassA .

(Of course, JavaScript doesn't have proper "subclasses", but this is obviously an attempt to implement class-based behavior in the language.)

purpose of calling ClassA's empty constructor inside ClassB's constructor using ".call()"

To have the script still working when ClassA will not be empty. Of course, currently it does nothing, but that might change in future. So it is good practise to implement the full inheritance pattern, making it easier to change the code later without introducing bugs.

Once ClassA changes to implement custom instance-specific properties - which are set up in the constructor, you want to have them on ClassB instances as well. Therefore, you invoke the ClassA constructor on ClassB instances as well during their initialisation.

If the ClassA constructor is empty (like in your example code), then yeah, it does nothing.

The reason you see this pattern though, is for the times when it's not. It's analogous to a super call in a class-based OO language.

If you have to do some work in the ClassA constructor to get an object that's in a correct state, it's likely you'll want to do the same work in a "subclass". Just copying the prototype's properties may not be enough.

With .call , you can change the value of this in the called method to the argument you specify. ClassA.call(this) calls the ClassA constructor with ClassB as the context. This allows you to use the properties of ClassB in ClassA methods. The methods are all copied to ClassB via ClassA.implementOn .

You will notice that (new ClassA()).dance() does nothing, but (new ClassB()).dance() alerts "dance" because this.canDance is true.

Demo: http://jsfiddle.net/5v7xh/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM