Emulate super in javascript

后端 未结 11 1143
生来不讨喜
生来不讨喜 2020-12-08 10:18

Basically is there a good elegant mechanism to emulate super with syntax that is as simple as one of the following

  • this.$super.prop()
11条回答
  •  心在旅途
    2020-12-08 10:51

    Note that for the following implementation, when you are inside a method that is invoked via $super, access to properties while working in the parent class never resolve to the child class's methods or variables, unless you access a member that is stored directly on the object itself (as opposed to attached to the prototype). This avoids a slew of confusion (read as subtle bugs).

    Update: Here is an implementation that works without __proto__. The catch is that using $super is linear in the number of properties the parent object has.

    function extend (Child, prototype, /*optional*/Parent) {
        if (!Parent) {
            Parent = Object;
        }
        Child.prototype = Object.create(Parent.prototype);
        Child.prototype.constructor = Child;
        for (var x in prototype) {
            if (prototype.hasOwnProperty(x)) {
                Child.prototype[x] = prototype[x];
            }
        }
        Child.prototype.$super = function (propName) {
            var prop = Parent.prototype[propName];
            if (typeof prop !== "function") {
                return prop;
            }
            var self = this;
            return function () {
                var selfPrototype = self.constructor.prototype;
                var pp = Parent.prototype;
                for (var x in pp) {
                    self[x] = pp[x];
                }
                try {
                    return prop.apply(self, arguments);
                }
                finally {
                    for (var x in selfPrototype) {
                        self[x] = selfPrototype[x];
                    }
                }
            };
        };
    }
    

    The following implementation is for browsers that support the __proto__ property:

    function extend (Child, prototype, /*optional*/Parent) {
        if (!Parent) {
            Parent = Object;
        }
        Child.prototype = Object.create(Parent.prototype);
        Child.prototype.constructor = Child;
        for (var x in prototype) {
            if (prototype.hasOwnProperty(x)) {
                Child.prototype[x] = prototype[x];
            }
        }
        Child.prototype.$super = function (propName) {
            var prop = Parent.prototype[propName];
            if (typeof prop !== "function") {
                return prop;
            }
            var self = this;
            return function (/*arg1, arg2, ...*/) {
                var selfProto = self.__proto__;
                self.__proto__ = Parent.prototype;
                try {
                    return prop.apply(self, arguments);
                }
                finally {
                    self.__proto__ = selfProto;
                }
            };
        };
    }
    

    Example:

    function A () {}
    extend(A, {
        foo: function () {
            return "A1";
        }
    });
    
    function B () {}
    extend(B, {
        foo: function () {
            return this.$super("foo")() + "_B1";
        }
    }, A);
    
    function C () {}
    extend(C, {
        foo: function () {
            return this.$super("foo")() + "_C1";
        }
    }, B);
    
    
    var c = new C();
    var res1 = c.foo();
    B.prototype.foo = function () {
        return this.$super("foo")() + "_B2";
    };
    var res2 = c.foo();
    
    alert(res1 + "\n" + res2);
    

提交回复
热议问题