26

I am wondering what's the difference between function and class. Both using the keyword function, is there obvious distinction between those two?

boulder_ruby
  • 33,076
  • 8
  • 66
  • 91
Adam Lee
  • 21,598
  • 43
  • 138
  • 208

7 Answers7

34

There is technically no class, they're both just functions. Any function can be invoked as a constructor with the keyword new and the prototype property of that function is used for the object to inherit methods from.

"Class" is only used conceptually to describe the above practice.

So when someone says to you "make a color class" or whatever, you would do:

function Color(r, g, b) {
    this.r = r;
    this.g = g;
    this.b = b;
}

Color.prototype.method1 = function() {

};

Color.prototype.method2 = function() {

};

When you break it down, there is simply a function and some assignments to a property called prototype of that function, all generic javascript syntax, nothing fancy going on.

It all becomes slightly magical when you say var black = new Color(0,0,0). You would then get an object with properties .r, .g and .b. That object will also have a hidden [[prototype]] link to Color.prototype. Which means you can say black.method1() even though .method1() does not exist in the black object.

Esailija
  • 130,716
  • 22
  • 250
  • 308
  • 1
    If that is so, why does React use the keyword class? here: https://www.tutorialspoint.com/reactjs/reactjs_jsx.htm – Harsha Apr 06 '17 at 10:13
  • 5
    @Harsha The class syntax has been added in ES6. They're still functions underneath though. – Feathercrown Dec 20 '18 at 15:10
  • **All**: Note that this answer is now outdated. Three years after it was posted, ES2015 added `class` syntax to JavaScript. See other answers that have been posted since. – T.J. Crowder Aug 25 '20 at 13:01
16

JavaScript is the most popular implementation of the ECMAScript Standard. The core features of Javascript are based on the ECMAScript standard, but Javascript also has other additional features that are not in the ECMA specifications/standard. Every browser has a JavaScript interpreter.


Overview

« ECMAScript was originally designed to be a Web scripting language, providing a mechanism to enliven Web pages in browsers and to perform server computation as part of a Web-based client-server architecture. A scripting language is a programming language that is used to manipulate, customize, and automate the facilities of an existing system.

ECMAScript is an object-oriented programming language for performing computations and manipulating computational objects within a host environment. A web browser provides an ECMAScript host environment for client-side computation including, for instance, objects that represent windows, menus, pop-ups, dialog boxes, text areas, anchors, frames, history, cookies, and input/output.

ECMAScript is object-based: basic language and host facilities are provided by objects, and an ECMAScript program is a cluster of communicating objects

Objects «

  • Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties.

  • Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” property. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain.


Function

JavaScript treats functions as first-class objects, so being an object, you can assign properties to a function.

Hoisting is the JavaScript interpreter’s action of moving all variable and function declarations to the top of the current scope. Function Hoisting, declarations & expressions

FunctionDeclaration : function BindingIdentifier ( FormalParameters ) { FunctionBody } FunctionExpression : function BindingIdentifier ( FormalParameters ) { FunctionBody }

ES5 Function:

function Shape(id) { // Function Declaration
    this.id = id;
};
// prototype was created automatically when we declared the function
Shape.hasOwnProperty('prototype'); // true

// Adding a prototyped method to a function.
Shape.prototype.getID = function () {
    return this.id;
};

var expFn = Shape; // Function Expression
console.dir( expFn () ); // Function Executes and return default return type - 'undefined'

To a function if the return value is not specified, then undefined is returned. If the function is invoked with new and the return value is not an object, then this (the new object) is returned.

NOTE: A prototype property is automatically created for every function, to allow for the possibility that the function will be used as a constructor.

  • constructor « Function object that creates and initializes objects.
  • prototype « object that provides shared properties for other objects.
  • __proto__ « The proto property which points to its super object's prototype. If you open it up you will see that proto points to its super object variables and functions.

To access prototype methods of above crated function, we need to create object using new keyword along with constructor function. if you are creating Shape - Object using new keyword then it has an internal (or) private link to function's prototype Shape.

ES5 Constructor Function Classes: Function objects created using Function.prototype.bind

Shape.prototype.setID = function ( id ) {
    this.id = id;
};

var funObj = new Shape( );
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 )
console.dir( funObj );

console.log( funObj.getID() );
/*
expFun                            funObj
    name: "Shape"                   id: 10
    prototype:Object
        constructor: function Shape(id)
        getID: function()
        setID: function( id )
    __proto__: function ()          __proto__: Object
                                        constructor: function Shape(id)
                                        getID: function()
                                        setID: function( id )
    <function scope>
*/

ES6 introduced Arrow function: An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors. ArrowFunction grammar production do not have a prototype property.

ArrowFunction : ArrowParameters => ConciseBody

  a => (a < 10) ? 'valid' : 'invalid'

  const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
    console.log( fn(2) ); // Even
    console.log( fn(3) ); // Odd

Class

In a class-based object-oriented language, in general, state is carried by instances, methods are carried by classes, and inheritance is only of structure and behavior. In ECMAScript, the state and methods are carried by objects, and structure, behavior, and state are all inherited.

Babel is a JavaScript compiler. Use it to Transform ES6 to ES5 format BABEL JS (or) ES6Console.

ES6 Classes: ES2015 classes are a simple sugar over the prototype-based OO pattern. Having a single convenient declarative form makes class patterns easier to use, and encourages interoperability. Classes support prototype-based inheritance, super calls, instance and static methods and constructors.

class Shape {
  constructor(id) {
    this.id = id
  }

  get uniqueID() {
    return this.id;
  }
  set uniqueID(changeVal) {
    this.id = changeVal;
  }
}
Shape.parent_S_V = 777;

// Class Inheritance
class Rectangle extends Shape {

  constructor(id, width, height) {
    super(id)
    this.width = width
    this.height = height
  }
  // Duplicate constructor in the same class are not allowed.
  /*constructor (width, height) { this._width  = width; this._height = height; }*/

  get area() {
    console.log('Area : ', this.width * this.height);
    return this.width * this.height
  }
  get globalValue() {
    console.log('GET ID : ', Rectangle._staticVar);
    return Rectangle._staticVar;
  }
  set globalValue(value) {
    Rectangle._staticVar = value;
    console.log('SET ID : ', Rectangle._staticVar);
  }

  static println() {
    console.log('Static Method');
  }

  // this.constructor.parent_S_V - Static property can be accessed by it's instances
  setStaticVar(staticVal) { // https://sckoverflow.com/a/42853205/5081877
    Rectangle.parent_S_V = staticVal;
    console.log('SET Instance Method Parent Class Static Value : ', Rectangle.parent_S_V);
  }

  getStaticVar() {
    console.log('GET Instance Method Parent Class Static Value : ', Rectangle.parent_S_V);
    return Rectangle.parent_S_V;
  }
}
Rectangle._staticVar = 77777;

var objTest = new Rectangle('Yash_777', 8, 7);
console.dir( objTest );

ES5 Function Classes: uses Object.defineProperty ( O, P, Attributes )

The Object.defineProperty() method defines a new property directly on an object, or modifies an existing property on an object, and returns the object.

Function instances that can be used as a constructor have a prototype property.

This property has the attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }.

    'use strict';
var Shape = function ( superClass ) {
    var currentClass = Shape;
    _inherits(currentClass, superClass); // Prototype Chain - Extends

    function Shape(id) { superClass.call(this); // Linking with SuperClass Constructor.
        // Instance Variables list.
        this.id = id;   return this;
    }
    var staticVariablesJOSN = { "parent_S_V" : 777 };
    staticVariable( currentClass, staticVariablesJOSN );

    // Setters, Getters, instanceMethods. [{}, {}];
    var instanceFunctions = [
        {
            key: 'uniqueID',
            get: function get() { return this.id; },
            set: function set(changeVal) { this.id = changeVal; }
        }
    ];
    instanceMethods( currentClass, instanceFunctions );

    return currentClass;
}(Object);

var Rectangle = function ( superClass ) {
    var currentClass = Rectangle;

    _inherits(currentClass, superClass); // Prototype Chain - Extends

    function Rectangle(id, width, height) { superClass.call(this, id); // Linking with SuperClass Constructor.

        this.width = width;
        this.height = height;   return this;
    }

    var staticVariablesJOSN = { "_staticVar" : 77777 };
    staticVariable( currentClass, staticVariablesJOSN );

    var staticFunctions = [
        {
            key: 'println',
            value: function println() { console.log('Static Method'); }
        }
    ];
    staticMethods(currentClass, staticFunctions);

    var instanceFunctions = [
        {
            key: 'setStaticVar',
            value: function setStaticVar(staticVal) {
                currentClass.parent_S_V = staticVal;
                console.log('SET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);
            }
        }, {
            key: 'getStaticVar',
            value: function getStaticVar() {
                console.log('GET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);
                return currentClass.parent_S_V;
            }
        }, {
            key: 'area',
            get: function get() {
                console.log('Area : ', this.width * this.height);
                return this.width * this.height;
                }
        }, {
            key: 'globalValue',
            get: function get() {
                console.log('GET ID : ', currentClass._staticVar);
                return currentClass._staticVar;
            },
            set: function set(value) {
                currentClass._staticVar = value;
                console.log('SET ID : ', currentClass._staticVar);
            }
        }
    ];
    instanceMethods( currentClass, instanceFunctions );

    return currentClass;
}(Shape);

// ===== ES5 Class Conversion Supported Functions =====
function defineProperties(target, props) {
    console.log(target, ' : ', props);
    for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
    }
}
function staticMethods( currentClass, staticProps ) {
    defineProperties(currentClass, staticProps);
};
function instanceMethods( currentClass, protoProps ) {
    defineProperties(currentClass.prototype, protoProps);
};
function staticVariable( currentClass, staticVariales ) {
    // Get Key Set and get its corresponding value.
    // currentClass.key = value;
    for( var prop in staticVariales ) {
        console.log('Keys : Values');
        if( staticVariales.hasOwnProperty( prop ) ) {
            console.log(prop, ' : ', staticVariales[ prop ] );
            currentClass[ prop ] = staticVariales[ prop ];
        }
    }
};
function _inherits(subClass, superClass) {
    console.log( subClass, ' : extends : ', superClass );
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, 
            { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });
    if (superClass)
        Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

var objTest = new Rectangle('Yash_777', 8, 7);
console.dir(objTest);

Below code snippet is to test about Each instance has their own copy of instance members and common static members.

var obj1 = new Rectangle('R_1', 50, 20);
Rectangle.println(); // Static Method
console.log( obj1 );    // Rectangle {id: "R_1", width: 50, height: 20}
obj1.area;              // Area :  1000
obj1.globalValue;       // GET ID :  77777
obj1.globalValue = 88;  // SET ID :  88
obj1.globalValue;       // GET ID :  88  

var obj2 = new Rectangle('R_2', 5, 70);
console.log( obj2 );    // Rectangle {id: "R_2", width: 5, height: 70}
obj2.area;              // Area :  350    
obj2.globalValue;       // GET ID :  88
obj2.globalValue = 999; // SET ID :  999
obj2.globalValue;       // GET ID :  999

console.log('Static Variable Actions.');
obj1.globalValue;        // GET ID :  999

console.log('Parent Class Static variables');
obj1.getStaticVar();    // GET Instance Method Parent Class Static Value :  777
obj1.setStaticVar(7);   // SET Instance Method Parent Class Static Value :  7
obj1.getStaticVar();    // GET Instance Method Parent Class Static Value :  7

Major Differences between functions and classes are:

  • Function Declarations get Hoisted to Top of the context, where as classes declarations and function Expressions are not Hoisted.
  • Function Declarations, Expression can be Overridden as they are like a Variable - var if multiple declaration are available then it overrides its parent scope. Where as the Classes are not Overridden they are like let | const, let doesn't allows multiple declaration with same name inside its scope.
  • Function's / classes allows only single constructor for its object scope.
  • Computed method names are allowed to ES6 classes having class keyword, but function keyword is not allows it

    function myFoo() {
     this.['my'+'Method'] = function () { console.log('Computed Function Method'); };
    }
    class Foo {
        ['my'+'Method']() { console.log('Computed Method'); }
    }
    
Yash
  • 7,342
  • 2
  • 55
  • 63
  • Now that [private fields](https://github.com/tc39/proposal-class-fields) and [private methods](https://github.com/tc39/proposal-private-methods) and such are progressing, `class` is no longer just syntactic sugar as it was when you originally posted your answer. – T.J. Crowder Aug 25 '20 at 13:04
7

In javascript, there are no classes. javascript uses prototype inheritance rather than class based inheritance. Many people will refer to classes in javascript because it is easier to understand, but it is purely an analogy.

In class based inheritance, you create a class (a "blueprint", if you will) and then instantiate objects from that class.

In prototype inheritance, an object is instantiated directly from another parent object, without ever needing any "blueprints".

See the wikipedia page for more information on Class vs Prototype inheritance.

jbabey
  • 42,963
  • 11
  • 66
  • 94
  • **All**: Note that this answer is now outdated. Three years after it was posted, ES2015 added `class` syntax to JavaScript. See other answers that have been posted since. – T.J. Crowder Aug 25 '20 at 13:02
4

Difference between a constructor function and class

The class keyword in javascript is very similar to a constructor function in the following manner:

  • They are both using javascript's prototypal inheritance system
  • They are both used to create objects with the following syntax: new myObj(arg1, arg2)

Constructor functions and classes are very alike can often be used interchangeably based on preference. However, javascript's private fields to classes is functionality which cannot be implemented by constructor functions (without scope hacks)

Example:

class PersonClass {
  constructor(name) {
    this.name = name;
  }
  
  speak () { console.log('hi'); }
}

console.log(typeof PersonClass); 
// logs function, a class is a constructor function under the hood.

console.log(PersonClass.prototype.speak);
// The class's methods are placed on the prototype of the PersonClass constructor function

const me = new PersonClass('Willem');

console.log(me.name); 
// logs Willem, properties assinged in the constructor are placed on the newly created object


// The constructor function equivalent would be the following:
function PersonFunction (name) {
  this.name = name;
}

PersonFunction.prototype.speak = function () { console.log('hi'); }
Willem van der Veen
  • 19,609
  • 11
  • 116
  • 113
  • 1
    this is exactly what I was asking myself. Thank you! – Adam Aug 15 '19 at 17:59
  • 1
    Now that [private fields](https://github.com/tc39/proposal-class-fields) and [private methods](https://github.com/tc39/proposal-private-methods) and such are progressing, `class` is no longer just syntactic sugar as it was when you originally posted your answer. – T.J. Crowder Aug 25 '20 at 13:04
  • Thanks for pointing this out T. J. Crowder, I have updated the answer. – Willem van der Veen Aug 27 '20 at 09:30
1

One key distinction between functions and classes was highlighted in this talk which suggests that a function is a behavior that can carry data while, inversely, a class is data that can carry behavior.

hyang123
  • 1,062
  • 1
  • 10
  • 27
0

The term class is usually used in an object-oriented programming language context. A class is a template of the object that will be created at instantiation. JavaScript is a prototype-based programming language, therefore it's a little strange to use the term class to describe a JavaScript prototype. In JavaScript prototypes are created as functions

Samuel
  • 15,583
  • 5
  • 54
  • 70
  • It would be strange if hardly anyone used term "class" like that, but apparently the opposite is true, so I do not see it as strange at all. We're basing objects on prototypes as we're basing them on classes/templates. – Jānis Elmeris Sep 23 '17 at 08:32
0

Class

A class declaration is scoped to its containing block. It is an error to declare a class name twice in the same block. Class definition are not hoisted.

Functions

Function declaration is block scope in strict mode.

The below table summarize the difference between class and function enter image description here

Srikrushna
  • 2,652
  • 30
  • 37