3

I have created below two employee classes, one using a constructor function and the other with JSON notation. In the constructor function, the print function is created by prototype so only one copy will be kept and objects (emp1 and emp2) share this print function.

Question: In the JSON notation (EmployeeNew), will the print function be held in memory as one copy only? Or will each object keep its own copy? What is the fundamental difference between these two approaches? Which is best for which scenario?

var Employee = function (name) {
    this.name = name;
};

Employee.prototype.print = function () {
    console.log(this.name);
}


var emp1 = new Employee("jack"),
    emp2 = new Employee("mark");

emp1.print();
emp2.print();

var EmployeeNew = {
    init: function (name) { this.name = name; },
    print: function () {
        console.log(this.name);
    }
};

var empNew1 = Object.create(EmployeeNew),
    empNew2 = Object.create(EmployeeNew)

empNew1.init("jack")
empNew1.print();
empNew2.init("jack");
empNew2.print();
4
  • 1
    JSON doesn't allow function syntax. You're using JavaScript object literal notation, not JSON. Commented Apr 12, 2012 at 17:42
  • You already wrote the "hard" code. Why don't you create a few objects with different values and see what turns up? Commented Apr 12, 2012 at 17:42
  • When you use prototype, all instances will use the same print function. The other way every instance will have it own print function (an copy). It depends on the usage what method you should use. Commented Apr 12, 2012 at 17:43
  • @BenniKa: The second example doesn't clone the EmployeeNew object. When you pass an object as the first argument to Object.create, that object becomes the prototype object of the new object being created, so the two examples are generally equivalent. Commented Apr 12, 2012 at 17:52

2 Answers 2

3

Your two code examples are generally equivalent (except for some minor details not relevant to the question).

This...

Object.create(EmployeeNew)

...creates a new object with the EmployeeNew object as its prototype. So the print and init functions are shared.

console.log(empNew1.init === empNew2.init); // true
console.log(empNew1.print === empNew2.print); // true

To further illustrate, here's an example that takes the following steps...

  1. Create an EmployeeNew object to be used by Object.create
  2. Create 2 unique objects using Object.create
  3. Verify that the new objects can use the functions provided by EmployeeNew
  4. Add a new function to EmployeeNew
  5. See if the objects from step 2 can use that new function

Step 1: Create an EmployeeNew object

var EmployeeNew = {
    init: function (name) { this.name = name; },
    print: function () {
        console.log(this.name);
    }
};

Step 2: Create 2 unique objects using Object.create

var empNew1 = Object.create(EmployeeNew),
    empNew2 = Object.create(EmployeeNew)

Step 3: Verify that the new objects can use the functions provided by EmployeeNew

empNew1.init("jack");
empNew1.print();
empNew2.init("jack");
empNew2.print();

Step 4: Add a new function to EmployeeNew

EmployeeNew.foo = function() {
    console.log( 'Foo was invoked' );
};

Step 5: See if the objects from step 2 can use that new function

empNew1.foo();  // logs 'Foo was invoked'
empNew2.foo();  // logs 'Foo was invoked'

So you can see that empNew1 and empNew2 are able to observe changes to EmployeeNew. This is because when we passed EmployeeNew as the first argument to Object.create, we created a new object with EmployeeNew set as the prototype of that object.

In simpler terms, when we look up a property, for example on empNew1, if empNew1 doesn't have that property, it automatically looks to its prototype to see if the property exists on that object. If so, it uses it.


With respect to your comment...

"...suppose, if create this.name as property ( name : "") is the name property also will be treated as prototype..."

Yes, if we do this...

EmployeeNew.name = "unknown"

...then that property will be shared among all instances that have EmployeeNew as their prototype object.

BUT

Because the .name property on the prototype is an immutable primitive value (a string), if we try to write to that property, what happens is that the .name property is automatically added directly to the instance.

Continuing with the example above...

EmployeeNew.name = "unknown";

Now the previously created instances will reference that property...

empNew1.name;  // "unknown"
empNew2.name;  // "unknown"

...but now lets update the property on one instance...

empNew1.name = "bubba";

empNew1.name;  // "bubba"
empNew2.name;  // "unknown"

This is because empNew1 now has its own .name property that references "bubba". This shadows the .name property on the prototype of empNew1, so the search for that property never extends into the prototype object.

Since empNew2 wasn't assigned a .name, it still looks to its prototype for that property.

Sign up to request clarification or add additional context in comments.

2 Comments

So is the print and init functions are treated as prototype functions? suppose, if create this.name as property ( name : "") is the name property also will be treated as prototype (value shared by all objects) i just want to know how do we create prototype and object functions in json notation?
@user845392: The point is that the same EmployeeNew object becomes the prototype object of both instances being created. This means that both instances automatically reference all the properties of the same EmployeeNew object, just like when using a constructor in your first example. Try this... after creating your two empNew objects, add a new function to the EmployeeNew object, then try to use that function on the empNew instances. You'll find that it works. This is because the empNew instances you created are (internally) referencing the same EmployeeNew object. I'll update.
0

Both cases are equivalent, you just need to think what seems more intuitive for your coding style, if creating a new object using new and all it's initial parameters, or using an init method.

One advantage of the Class implementation is that, if you compose your object inside the Class definition (I know, it's not prototype-like) you can create inner private attributes, which using just prototype you can't (unless you flag them using a special notation like an underscore prefix). In the end is just a matter of style and what do you feel more comfortable with.

2 Comments

i couldn't understand fully in your response. Can you give a example for explaining underscore prefix?
Using pure prototype definition does not allow you to hide attributes as private. Instead of that you prefix them with a marker, usually an underscore, to let know that that attribute is not intended to use it as a public attribute, but as a private/internal one. It's just a naming convetion.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.