Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript: what's the difference between a function and a class

Tags:

javascript

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

like image 342
Adam Lee Avatar asked Aug 15 '12 13:08

Adam Lee


People also ask

What is the difference between a function and a class?

Functions do specific things, classes are specific things. Classes often have methods, which are functions that are associated with a particular class, and do things associated with the thing that the class is - but if all you want is to do something, a function is all you need.

What is the difference between constructor function and class in JavaScript?

Functions are first-class in JavaScript, and they can have properties or be properties of other objects. A class constructor creates an instance of the class. A constructor in JavaScript is just a plain old function that returns an object.

When should I use classes instead of functions?

As a rule of thumb, when you have a set of data with a specific structure and you want to perform specific methods on it, use a class. That is only valid, however, if you use multiple data structures in your code. If your whole code won't ever deal with more than one structure.

Are classes in JavaScript functions?

Classes are in fact "special functions", and just as you can define function expressions and function declarations, the class syntax has two components: class expressions and class declarations.


2 Answers

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.

like image 102
Esailija Avatar answered Sep 21 '22 00:09

Esailija


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'); } } 
  • JSON object & Object Literal
like image 39
Yash Avatar answered Sep 20 '22 00:09

Yash