Instancing new objects in javascript

2019-08-13 14:41发布

问题:

I'm probably missing something really basic on javascript knowledge, but why doesn't this work?

var person = {

    name:"",
    age:0,

    set : function(name,age){
        this.name = name;
        this.age = age;
    }
}

var me = new person; // ERROR: Object doesn't support this action!
me.set('Victor',12);
me.name //Victor

But this does:

var person = function(){

    this.name="";
    this.age=0;

    this.set = function(name,age){
        this.name=name;
        this.age=age;
    }
}

var me = new person(); //WORKS!
me.set('Victor',12);
me.name; //Victor

回答1:

Your first example was an object literal:

var person = {
    name: "Bob",
    //etc
};

You've created a single object called person, and that's that. The concept of creating new persons has no meaning.

If you want to create something that can be used to create more objects at will, you'd use a function, like your second example.

Note though that functions intended to be used as a constructor start with a capital letter by convention. Also note that when you set a function inside of your constructor using

this.functionName = function() .....

this creates a privileged function, since it has access to both public, and private members. If this set function only needs access to public properties, it would usually be added to the function's prototype. Here's how the whole thing might look

function Person() {
    this.name = "";
    this.age = 0;
};

Person.prototype.set = function(name,age) {
    this.name = name;
    this.age = age;
}

And here's what a privileged method might look like

function Person() {
    var localData = "Hello";

    this.showPrivateData = function() {
        alert(localData);
    };

    this.name="";
    this.age=0;
};

localData is local to the Person function, and cannot be accessed as a property on instances of Person; however, the showPrivateData function, and any other privileged functions you might add, would form a closure over it, and have access to it.

Finally, note that constructor functions can take parameters:

function Person(name, age) {
    this.name= name;
    this.age= age;
};


回答2:

You answer your own question. A constructor (the thing that goes next to new) must be a function in JavaScript.



回答3:

JavaScript has no classes (although you can simulate them), this is why. And new works only on functions (in this case it creates special variable this inside function, which is being returned implicitly after function call).

So, when using this:

var person = {
    name:"",
    age:0,
    set : function(name,age){
        this.name = name;
        this.age = age;
    }
};

you already create an object (which has a function as one of its properties).

But when you use this:

var person = function(){
    this.name="";
    this.age=0;
    this.set = function(name,age){
        this.name=name;
        this.age=age;
    }
};

you only create function, that returns this with all assigned properties when the function is called with new.

What documentation says

As documentation of new operator on Mozilla Developer Network says:

The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.

...

Creating a user-defined object requires two steps:

  • Define the object type by writing a function.
  • Create an instance of the object with new.

and you basically make both steps in the second case.



回答4:

The first version uses an object literal to create a single object instance which is assigned to person. This cannot be used like a constructor with new to create other objects from person.

The second version uses a function, which can be called as a constructor to create new objects with new person().

That's just the way new works in JavaScript. Essentially if you want to be able to create multiple instances from a template (similar to how classes work in other languages) then use the new FunctionName() syntax. If you only need to create a single instance of a particular object you can use the first syntax.

Note that in the first version you can say:

person.set('Victor',12);
alert(person.name); // 'Victor'

Note also that if you are creating a function that is intended for use as a constructor the convention is to use uppercase for the first letter of its name (or the first letter of each word in the name).