简体   繁体   中英

javascript OOP - how come argument object is not visible from instance method?

I created jQuery dialog classes.

Base class is AlertDialog . Child class is ChildAlertDialog .

When ChildAlertDialog is instantiated, it takes elementId (DOM id) and executor object (MyExcecutor instance), and show alert looking dialog with close button.

Close button triggers MyExecutor's instance method executeClose();

But when I call:

alertbox.displayDialog();

I get an error:

executor is undefined
executor.executeClose();

It works if I pass executor to displayDialog() method. So I'm bit confused because it would work in other language like Java but javascript seems different. Should I just pass executor to displayDialog()? Or is there better way?

------ dialog class ------------

//base class
function AlertDialog(elementId, executor) {
    this.elementId = elementId;
    this.height = null;
    this.width = null;

    this.displayDialog = function() {
        $(this.elementId).dialog({
            autoOpen: true,
            height: this.height,
            width: this.width,
            buttons: {
                'close me': function() {
                    executor.executeClose(); //ERROR HERE!!!!!
                }
            }
        });
}

//child class
function ChildAlertDialog(elementId, executor) {
    this.elementId = elementId;
    this.height = 70;
    this.width = 400;
}

//inheritance
ChildAlertDialog.prototype = new AlertDialog();
ChildAlertDialog.prototype.constructor = ChildAlertDialog;

The class that uses ChildAlertDialog class.

function MyExcecutor() {

    this.execute = function() {
        //passing elementID and MyExecutor object to ChildAlertDialog
        var alertbox = new ChildAlertDialog("#someDiv",this);
        alertbox.displayDialog();
    }

    this.executeClose = function() {
        //do something when the dialog is closed
    }
}

The scope of a function argument is only that function. When you invoke the ChildAlertDialog constructor during object creation, executor is only accessible within ChildAlertDialog .

To ensure the executor is accessible to displayDialog , either explicitly call AlertDialog :

function ChildAlertDialog(elementId, executor) {
    AlertDialog.call(this, elementId, executor);
    this.height = 70;
    this.width = 400;
}

or make executor a property of the dialog object.

function AlertDialog(elementId, executor) {
    this.executor = executor;
    ...

    this.displayDialog = function() {
        ...
                    this.executor.executeClose();
}

//child class
function ChildAlertDialog(elementId, executor) {
    this.executor = executor;
    ...
}

This problem, the lack of separation between creation of prototypes and object initialization , was what lead Douglas Crockford to develop Object.create , which is now becoming a standard , browser native JS function.

function AlertDialog(elementId, executor) {
    this.elementId = elementId;
    this.executor = executor;
}
AlertDialog.prototype.height = null;
AlertDialog.prototype.width = null;
AlertDialog.prototype.displayDialog = function() {
    $(this.elementId).dialog({
        autoOpen: true,
        height: this.height,
        width: this.width,
        buttons: {
            'close me': function() {
                this.executor.executeClose();
            }
        }
    });
};


//child class
function ChildAlertDialog(elementId, executor) {
    AlertDialog.call(this, elementId, executor);
    this.height = 70;
    this.width = 400;
}

//inheritance
ChildAlertDialog.prototype = Object.create(AlertDialog.prototype, 
        {constructor: {value: ChildAlertDialog, writable: false, enumerable: false}});

You override the constructor function, and never call the original version which sets this up. Your first constructor function which binds the executor in the scope of the instance never actually runs . So you have to call it, and the syntax is a little odd.

Try this instead, which calls the original version:

//child class
function ChildAlertDialog(elementId, executor) {
    // Run the parent constructor function
    AlertDialog.call(this, elementId, executor);

    // Child class setup.
    this.elementId = elementId;
    this.height = 70;
    this.width = 400;
}

//inheritance
ChildAlertDialog.prototype = new AlertDialog();
ChildAlertDialog.prototype.constructor = ChildAlertDialog;

You have to use ConstructorFunction.call(this, args...) in order to run the constructor function on the instance. Sadly prototypes and constructor functions inherit in very different ways. And this is why setting up instance methods in the constructor is usually a bad idea.

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