Constructors in JavaScript objects

2018-12-31 09:30发布

Can JavaScript classes/objects have constructors? How are they created?

19条回答
看淡一切
2楼-- · 2018-12-31 09:50

They do if you use Typescript - open source from MicroSoft :-)

class BankAccount {
 balance: number;
 constructor(initially: number) {
 this.balance = initially;
 }
 deposit(credit: number) {
 this.balance += credit;
 return this.balance;
 }
}

Typescript lets you 'fake' OO constructs that are compiled into javascript constructs. If you're starting a large project it may save you a lot of time and it just reached milestone 1.0 version.

http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf

The above code gets 'compiled' to :

var BankAccount = (function () {
    function BankAccount(initially) {
        this.balance = initially;
    }
    BankAccount.prototype.deposit = function (credit) {
        this.balance += credit;
        return this.balance;
    };
    return BankAccount;
})();
查看更多
浮光初槿花落
3楼-- · 2018-12-31 09:52

Here's a template I sometimes use for OOP-similar behavior in JavaScript. As you can see, you can simulate private (both static and instance) members using closures. What new MyClass() will return is an object with only the properties assigned to the this object and in the prototype object of the "class."

var MyClass = (function () {
    // private static
    var nextId = 1;

    // constructor
    var cls = function () {
        // private
        var id = nextId++;
        var name = 'Unknown';

        // public (this instance only)
        this.get_id = function () { return id; };

        this.get_name = function () { return name; };
        this.set_name = function (value) {
            if (typeof value != 'string')
                throw 'Name must be a string';
            if (value.length < 2 || value.length > 20)
                throw 'Name must be 2-20 characters long.';
            name = value;
        };
    };

    // public static
    cls.get_nextId = function () {
        return nextId;
    };

    // public (shared across instances)
    cls.prototype = {
        announce: function () {
            alert('Hi there! My id is ' + this.get_id() + ' and my name is "' + this.get_name() + '"!\r\n' +
                  'The next fellow\'s id will be ' + MyClass.get_nextId() + '!');
        }
    };

    return cls;
})();

I've been asked about inheritance using this pattern, so here goes:

// It's a good idea to have a utility class to wire up inheritance.
function inherit(cls, superCls) {
    // We use an intermediary empty constructor to create an
    // inheritance chain, because using the super class' constructor
    // might have side effects.
    var construct = function () {};
    construct.prototype = superCls.prototype;
    cls.prototype = new construct;
    cls.prototype.constructor = cls;
    cls.super = superCls;
}

var MyChildClass = (function () {
    // constructor
    var cls = function (surName) {
        // Call super constructor on this instance (any arguments
        // to the constructor would go after "this" in call(…)).
        this.constructor.super.call(this);

        // Shadowing instance properties is a little bit less
        // intuitive, but can be done:
        var getName = this.get_name;

        // public (this instance only)
        this.get_name = function () {
            return getName.call(this) + ' ' + surName;
        };
    };
    inherit(cls, MyClass); // <-- important!

    return cls;
})();

And an example to use it all:

var bob = new MyClass();
bob.set_name('Bob');
bob.announce(); // id is 1, name shows as "Bob"

var john = new MyChildClass('Doe');
john.set_name('John');
john.announce(); // id is 2, name shows as "John Doe"

alert(john instanceof MyClass); // true

As you can see, the classes correctly interact with each other (they share the static id from MyClass, the announce method uses the correct get_name method, etc.)

One thing to note is the need to shadow instance properties. You can actually make the inherit function go through all instance properties (using hasOwnProperty) that are functions, and automagically add a super_<method name> property. This would let you call this.super_get_name() instead of storing it in a temporary value and calling it bound using call.

For methods on the prototype you don't need to worry about the above though, if you want to access the super class' prototype methods, you can just call this.constructor.super.prototype.methodName. If you want to make it less verbose you can of course add convenience properties. :)

查看更多
初与友歌
4楼-- · 2018-12-31 09:53

Using Nick's sample above, you can create a constructor for objects without parameters using a return statement as the last statement in your object definition. Return your constructor function as below and it will run the code in __construct each time you create the object:

function Box()
{
   var __construct = function() {
       alert("Object Created.");
       this.color = 'green';
   }

  this.color = '';

   this.getColor = function() {
       return this.color;
   }

   __construct();
}

var b = new Box();
查看更多
其实,你不懂
5楼-- · 2018-12-31 09:57

Using prototypes:

function Box(color) // Constructor
{
    this.color = color;
}

Box.prototype.getColor = function()
{
    return this.color;
};

Hiding "color" (somewhat resembles a private member variable):

function Box(col)
{
   var color = col;

   this.getColor = function()
   {
       return color;
   };
}

Usage:

var blueBox = new Box("blue");
alert(blueBox.getColor()); // will alert blue

var greenBox = new Box("green");
alert(greenBox.getColor()); // will alert green
查看更多
时光乱了年华
6楼-- · 2018-12-31 09:58

So what is the point of "constructor" property? Cannot figure out where it could be useful, any ideas?

The point of the constructor property is to provide some way of pretending JavaScript has classes. One of the things you cannot usefully do is change an object's constructor after it's been created. It's complicated.

I wrote a fairly comprehensive piece on it a few years ago: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html

查看更多
爱死公子算了
7楼-- · 2018-12-31 10:00

In JavaScript the invocation type defines the behaviour of the function:

  • Direct invocation func()
  • Method invocation on an object obj.func()
  • Constructor invocation new func()
  • Indirect invocation func.call() or func.apply()

The function is invoked as a constructor when calling using new operator:

function Cat(name) {
   this.name = name;
}
Cat.prototype.getName = function() {
   return this.name;
}

var myCat = new Cat('Sweet'); // Cat function invoked as a constructor

Any instance or prototype object in JavaScript have a property constructor, which refers to the constructor function.

Cat.prototype.constructor === Cat // => true
myCat.constructor         === Cat // => true

Check this post about constructor property.

查看更多
登录 后发表回答