Features of ES6 Part 10: Behind The Class

Tuesday, November 11, 2014

In a previous post we looked at the new class keyword in JavaScript.

We’ve always had the ability to create objects in JavaScript, and give these objects data to hold and methods to call. In fact, we could have written an “employee” object using a simple object literal instead of a class.

let developer = { 
    name: "Scott", 
    doWork: function() { 
        return `${this._name} is working`; 
    }, 

    get name() { 
        return this._name.toUpperCase(); 
    }, 

    set name(newName) { 
        if(newName) { 
            this._name = newName; 
        } 
    } 

}; 

expect(developer.name).toBe("SCOTT"); 

developer.name = "Alex"; 
expect(developer.doWork()).toBe("Alex is working");

The advantage to having a class is how we can create multiple developers just by using the new keyword and not have to write out an entire literal definition like the above code. Each object is unique and contains its own data, but the method implementations are consistent and shared.

let dev1 = new Employee("Scott"); 
let dev2 = new Employee("Alex");

In fact, even before the class keyword came along, we had the ability to define a blueprint for object construction in JavaScript. The approach was one we called the “constructor function and prototype object” approach.

let Employee = function(name) { 
    this._name = name; 
}; 

Employee.prototype = { 

    doWork: function() { 
        return `${this._name} is working`; 
    }, 

    get name() { 
        return this._name.toUpperCase(); 
    }, 

    set name(newName) { 
        if(newName) { 
            this._name = newName; 
        } 
    } 
}; 

let developer = new Employee("Scott"); 
expect(developer.name).toBe("SCOTT");

As it turns out, all the class keyword is doing behind the scenes is setting up a constructor function and prototype object. This means all of the tricks we’ve learned in the past still work. For example, “borrowing” a method from a prototype object:

class A { 

    doWork() { 
        return "complete!"; 
    } 

} 

var result = A.prototype.doWork.call(); 
expect(result).toBe("complete!");

The instanceof operator also works as expected.

class A { 
    // … 
} 

var a = new A(); 

expect(a instanceof A).toBe(true); 
expect(a instanceof Object).toBe(true);

You can also still augment all instances of a type by modifying prototype objects (if you like to live dangerously).

class A { 

} 

A.prototype.newMethod = function() { 
    return "new!"; 
}; 

var a = new A(); 
expect(a.newMethod()).toBe("new!");

You can think of the class keyword as being syntactic sugar for creating constructor functions and prototype objects. However, there is more to the class keyword than what we’ve seen so far. We’ll look at class inheritance in the next post.


Comments
gravatar George mauer Sunday, November 30, 2014
So no information hiding via private/protected access modifiers then? Great, now we get yet another generation of js developers who claim they're doing oop while having no idea what they're talking about. Short of some inconsequential preformance boosts it seems like the class keyword might continue being inferior or just making a factory method that returns a regular js object.
Comments are closed.

My Pluralsight Courses

K.Scott Allen OdeToCode by K. Scott Allen
What JavaScript Developers Should Know About ECMAScript 2015
The Podcast!