简体   繁体   中英

Sealed methods in javascript

I am creating a slideshow that use Transition objects to transition slides:

function Transition(slide, settings){
    this.slide = slide;
    this.el = slide.el;
    this.settings = settings;
    this.duration = (this.settings['transitionSpeed'] / 1000) + 's';
    this.endAnimation = null;
}

Transition.prototype.inRight = function(callback){
    callback();
}

Transition.prototype.outRight = function(callback){
    callback();
}

Transition.prototype.inLeft = function(callback){
    callback();
}

Transition.prototype.outLeft = function(callback){
    callback();
}

Each of the methods correspond to how the slide should behave should it be transitioning in from the right, out to the right, in from the left, and out to the left. All well and good when the Transition is acting upon slides:

function ClassBasedTransition(slide, settings, transitionName){
    Transition.call(this, slide, settings);
    this.transitionName = transitionName;
}

ClassBasedTransition.prototype = Object.create(Transition.prototype);
ClassBasedTransition.prototype.constructor = ClassBasedTransition;

ClassBasedTransition.prototype.inRight = function(callback){
    var self = this;
    this.endAnimation = function(){
        DomUtil.removeClass(this, 'nd-' + self.transitionName + '-in-right-transition');
        callback();
        this.removeEventListener( 'webkitAnimationEnd', bound );
    }

    var bound = this.endAnimation;
    this.el.style.webkitAnimationDuration = this.duration;

    this.el.addEventListener( 'webkitAnimationEnd', bound);
    DomUtil.addClass(this.el, 'nd-' + this.transitionName + '-in-right-transition');
}

 **SNIP**

However, as I have been introducing 3D transitions, I am actually transitioning on the gallery container, and not individual slides, it makes less sense to have four transitions, and instead to only have two:

 //3 DIMENSIONAL TRANSITION
function D3Transition(slide, settings, transitionName){
    Transition.call(this, slide, settings);
    this.transitionName = transitionName;

    this.galleryEl = slide.gallery.el;
    if(!DomUtil.hasClass(this.galleryEl, 'nd-' + transitionName + '-gallery'))
        DomUtil.addClass(this.galleryEl, 'nd-' + transitionName + '-gallery');
}

D3Transition.prototype = Object.create(Transition.prototype);
D3Transition.prototype.constructor = D3Transition;

D3Transition.prototype.inRight = function(callback){
     **APPLY 3D EFFECT FORWARD**
}

D3Transition.prototype.inLeft = function(callback){
        **EFFECT 3D EFFECT IN REVERSE**
    }

D3Transition.prototype.outLeft = function(callback){
     **NO OP**
}

D3Transition.prototype.outRight = function(callback){
        **NO OP**
    }

Is there some way to seal D3Transition.prototype.outLeft and D3Transition.prototype.outRight so that derived objects cannot implement them? I know we can seal objects in javascript, is there some way to seal individual prototype functions?

You can make a property not writable so it can't be modified by the inheriting class:

Object.defineProperty(D3Transition.prototype, 'outLeft', {
  value    : function(){},
  writable : false
});

Demo with two ways of doing it: http://jsbin.com/paqehera/1/edit

This solution prevents direct assignments to the outLeft property from having any effect both on the inheriting class prototype and on instances of either class. However, the solution is not perfect, because the property can be redefined on the prototype or instances using Object.defineProperty again (as mentioned in the comment by Benjamin Gruenbaum).

The moment you make outLeft and outRight just functions

var outLeft = function() {};

Instead of prototypes, it turns into a 'private' method, meaning it can only be used inside D3Transition. You do however need to implememt it like this:

function d3Transition() {
    var outLeft = function() {};
}

Derived objects can't access the method, but it can be accessed from inside D3Transition, basically making it private.

I believe this is what you needed.

If you don't want the D3Transistion to have no outLeft and outRight you can set them to null or undefined as trying to call it will throw an error but it'll still show up in the properties list.

D3Transition.prototype.outLeft = D3Transition.prototype.outRight = null;

You're basically shadowing it by having the functions lower down the prototype chain so Transition.prototype.outLeft will not be used for instances of D3Transition or objects inheriting from it.

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