Last active
April 8, 2020 22:55
-
-
Save tomchen/1850ff92f9bf494ba625cbf2843ec1d8 to your computer and use it in GitHub Desktop.
ES6 class vs ES5 constructor function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//ES6 class vs ES5 constructor function | |
// ES6 class | |
class MyClass { | |
// is executed upon instantiation, not to be used as a normal method | |
// proposal class properties | |
// https://babeljs.io/docs/en/babel-plugin-proposal-class-properties | |
// https://github.com/tc39/proposal-class-fields | |
publicVariable = "public variable"; | |
#privateVariable = "private variable"; | |
static staticPublicVariable = "static public variable"; | |
static #staticPrivateVariable = "static private variable"; | |
constructor(arg1, arg2) { | |
console.log("constructor executed!"); | |
var _privateVarInConstructor = "private var in constructor"; | |
this.publicVar = "public var"; | |
// The only privilege ES5 constructor function's privileged method has | |
// comparing to normal public method is: to access _privateVarInClass, arg1(, arg2...), and _privateVarInConstructor | |
this.privilegedMethod = function() { | |
// here shows the context during a "normal" call, it could change when it's called differently (such as using bind/apply/call). Same as below | |
console.log(this === myclassinstance); // true | |
// the following tests have exactly the same output as the tests in constructor | |
console.log(this.constructor === MyClass); // true | |
try{ console.log(_privateVarInConstructor); }catch(e){console.log("NOT DECLARED");} // private var in constructor | |
try{ console.log(arg1); }catch(e){console.log("NOT DECLARED");} // arg 1 | |
try{ console.log(publicVar); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(this.publicVar); }catch(e){console.log("NOT DECLARED");} // public var | |
try{ console.log(MyClass.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.method2(); }catch(e){console.log("NOT DECLARED");} // method2 executed! | |
try{ MyClass.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ MyClass.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // staticMethod2 executed! | |
} | |
// access to the variables and methods outside the constructor is exactly the same as normal public method | |
console.log(this); // the context (this) is the newly created instance of the class and will later be referenced by the variable "myclassinstance" | |
console.log(this.constructor === MyClass); // true | |
try{ console.log(_privateVarInConstructor); }catch(e){console.log("NOT DECLARED");} // private var in constructor | |
try{ console.log(arg1); }catch(e){console.log("NOT DECLARED");} // arg 1 | |
try{ console.log(publicVar); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(this.publicVar); }catch(e){console.log("NOT DECLARED");} // public var | |
try{ console.log(MyClass.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.method2(); }catch(e){console.log("NOT DECLARED");} // method2 executed! | |
try{ MyClass.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ MyClass.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // staticMethod2 executed! | |
} | |
// var _privateVarInClass = "private var in class"; // not allowed in ES6, OK in ES5 | |
// var _privateMethod = function() { // not allowed in ES6, OK in ES5 | |
// }; | |
publicMethod0 = () => {} // NOT yet supported by lastest Chrome | |
publicMethod() {} | |
#privateMethod() {} // NOT yet supported by lastest Chrome (privateVariable is supported) | |
static staticPublicMethod() {} | |
static #staticPrivateMethod() {} // NOT yet supported by lastest Chrome (staticPrivateVariable is supported) | |
// normal public method, to be called with myclassinstance.method1(); | |
method1() { | |
console.log(this === myclassinstance); // true | |
console.log(this.constructor === MyClass); // true | |
try{ console.log(_privateVarInConstructor); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED // can't access _privateVarInConstructor by any means | |
try{ console.log(arg1); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED // can't access arg1 by any means | |
try{ console.log(publicVar); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(this.publicVar); }catch(e){console.log("NOT DECLARED");} // public var | |
try{ console.log(MyClass.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.method2(); }catch(e){console.log("NOT DECLARED");} // method2 executed! | |
try{ MyClass.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ MyClass.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // staticMethod2 executed! | |
} | |
method2() { | |
console.log("method2 executed!"); | |
} | |
// static public method, to be called only with MyClass.staticMethod1(); | |
static staticMethod1() { | |
console.log(this === MyClass); // true | |
console.log(this.constructor === Function); // true | |
try{ console.log(_privateVarInConstructor); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED // can't access _privateVarInConstructor by any means | |
try{ console.log(arg1); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED // can't access arg1 by any means | |
try{ console.log(publicVar); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(this.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(this.constructor.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.constructor.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // staticMethod2 executed! | |
try{ this.constructor.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
} | |
static staticMethod2() { | |
console.log("staticMethod2 executed!"); | |
} | |
static staticMethod2() { | |
console.log("staticMethod2 executed!"); | |
} | |
// static staticVariable = 42; // proposed, not widely supported yet. (static variable is another name for static property here) We can either use MyClass.staticVariable outside the class, or use: | |
// static get staticVariable() { | |
// return 5; | |
// } | |
} | |
console.log(" ========== BEGINNING OF var myclassinstance = new MyClass(); ========== "); | |
var myclassinstance = new MyClass("arg 1"); | |
console.log(" ========== END OF var myclassinstance = new MyClass(); ========== "); | |
// MyClass.method1(); // can't access | |
console.log(" ========== BEGINNING OF myclassinstance.method1(); ========== "); | |
myclassinstance.method1(); | |
console.log(" ========== END OF myclassinstance.method1(); ========== "); | |
// myclassinstance.staticMethod1(); // can't access | |
console.log(" ========== BEGINNING OF MyClass.staticMethod1(); ========== "); | |
MyClass.staticMethod1(); | |
console.log(" ========== END OF MyClass.staticMethod1(); ========== "); | |
// MyClass.privilegedMethod(); // can't access | |
console.log(" ========== BEGINNING OF myclassinstance.privilegedMethod(); ========== "); | |
myclassinstance.privilegedMethod(); | |
console.log(" ========== END OF myclassinstance.privilegedMethod(); ========== "); | |
console.log(MyClass.prototype); // { constructor: ..., method1: ..., method2: ..., ...} | |
// ES5 constructor function | |
"use strict"; | |
var UrClass = function () { | |
// is executed upon instantiation, not to be used as a normal method | |
function UrClass(arg1, arg2) { | |
if (!(this instanceof UrClass)) { throw new TypeError("Cannot call a class as a function"); } // added to simulate the class' behaviour in ES6 | |
console.log("constructor executed!"); | |
var _privateVarInConstructor = "private var in constructor"; | |
this.publicVar = "public var"; | |
// The only privilege ES5 constructor function's privileged method has | |
// comparing to normal public method is: to access _privateVarInClass, arg1(, arg2...), and _privateVarInConstructor | |
this.privilegedMethod = function () { | |
// here shows the context during a "normal" call, it could change when it's called differently (such as using bind/apply/call). Same as below | |
console.log(this === urclassinstance); // true | |
// the following tests have exactly the same output as the tests in constructor | |
console.log(this.constructor === UrClass); // true | |
try{ console.log(_privateVarInConstructor); }catch(e){console.log("NOT DECLARED");} // private var in constructor | |
try{ console.log(arg1); }catch(e){console.log("NOT DECLARED");} // arg 1 | |
try{ console.log(publicVar); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(this.publicVar); }catch(e){console.log("NOT DECLARED");} // public var | |
try{ console.log(UrClass.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(_privateVarInClass); }catch(e){console.log("NOT DECLARED");} // private var in class | |
try{ console.log(this._privateVarInClass); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(UrClass._privateVarInClass); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.method2(); }catch(e){console.log("NOT DECLARED");} // method2 executed! | |
try{ UrClass.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ UrClass.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // staticMethod2 executed! | |
}; | |
// access to the variables and methods outside the constructor is exactly the same as normal public method | |
console.log(this); // the context (this) is the newly created instance of the class and will later be referenced by the variable "urclassinstance" | |
console.log(this.constructor === UrClass); // true | |
try{ console.log(_privateVarInConstructor); }catch(e){console.log("NOT DECLARED");} // private var in constructor | |
try{ console.log(arg1); }catch(e){console.log("NOT DECLARED");} // arg 1 | |
try{ console.log(publicVar); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(this.publicVar); }catch(e){console.log("NOT DECLARED");} // public var | |
try{ console.log(UrClass.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(_privateVarInClass); }catch(e){console.log("NOT DECLARED");} // private var in class | |
try{ console.log(this._privateVarInClass); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(UrClass._privateVarInClass); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.method2(); }catch(e){console.log("NOT DECLARED");} // method2 executed! | |
try{ UrClass.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ UrClass.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // staticMethod2 executed! | |
} | |
var _privateVarInClass = "private var in class"; // not allowed in ES6, OK in ES5 | |
// not allowed in ES6, OK in ES5 | |
// it can be called from anywhere inside the class | |
// (i.e. directly in the class (at the end) / in the privileged method / | |
// constructor / other private method / normal or static public method) | |
// the result is always the same as in the following comments | |
var _privateMethod = function() { | |
console.log(this); // Window | |
try{ console.log(_privateVarInConstructor); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(arg1); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(publicVar); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(this.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(UrClass.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(UrClass.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(_privateVarInClass); }catch(e){console.log("NOT DECLARED");} // private var in class | |
try{ console.log(this._privateVarInClass); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(UrClass._privateVarInClass); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ UrClass.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ UrClass.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // staticMethod2 executed! | |
}; | |
// normal public method, to be called with urclassinstance.method1(); | |
UrClass.prototype.method1 = function() { | |
console.log(this === urclassinstance); // true | |
console.log(this.constructor === UrClass); // true | |
try{ console.log(_privateVarInConstructor); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED // can't access _privateVarInConstructor by any means | |
try{ console.log(arg1); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED // can't access arg1 by any means | |
try{ console.log(publicVar); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(this.publicVar); }catch(e){console.log("NOT DECLARED");} // public var | |
try{ console.log(UrClass.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(_privateVarInClass); }catch(e){console.log("NOT DECLARED");} // private var in class | |
try{ console.log(this._privateVarInClass); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(UrClass._privateVarInClass); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.method2(); }catch(e){console.log("NOT DECLARED");} // method2 executed! | |
try{ UrClass.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ UrClass.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // staticMethod2 executed! | |
}; | |
UrClass.prototype.method2 = function() { | |
console.log("method2 executed!"); | |
}; | |
// static public method, to be called only with UrClass.staticMethod1(); | |
UrClass.staticMethod1 = function() { | |
console.log(this === UrClass); // true | |
console.log(this.constructor === Function); // true | |
try{ console.log(_privateVarInConstructor); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED // can't access _privateVarInConstructor by any means | |
try{ console.log(arg1); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED // can't access arg1 by any means | |
try{ console.log(publicVar); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ console.log(this.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(this.constructor.publicVar); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(_privateVarInClass); }catch(e){console.log("NOT DECLARED");} // private var in class | |
try{ console.log(this._privateVarInClass); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ console.log(UrClass._privateVarInClass); }catch(e){console.log("NOT DECLARED");} // undefined | |
try{ method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.constructor.method2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
try{ this.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // staticMethod2 executed! | |
try{ this.constructor.staticMethod2(); }catch(e){console.log("NOT DECLARED");} // NOT DECLARED | |
}; | |
UrClass.staticMethod2 = function() { | |
console.log("staticMethod2 executed!"); | |
}; | |
//same goes for UrClass.staticVariable (static variable is another name for static property here) | |
return UrClass; | |
}(); | |
console.log(" ========== BEGINNING OF var urclassinstance = new UrClass(); ========== "); | |
var urclassinstance = new UrClass("arg 1"); | |
console.log(" ========== END OF var urclassinstance = new UrClass(); ========== "); | |
// UrClass.method1(); // can't access | |
console.log(" ========== BEGINNING OF urclassinstance.method1(); ========== "); | |
urclassinstance.method1(); | |
console.log(" ========== END OF urclassinstance.method1(); ========== "); | |
// urclassinstance.staticMethod1(); // can't access | |
console.log(" ========== BEGINNING OF UrClass.staticMethod1(); ========== "); | |
UrClass.staticMethod1(); | |
console.log(" ========== END OF UrClass.staticMethod1(); ========== "); | |
// UrClass.privilegedMethod(); // can't access | |
console.log(" ========== BEGINNING OF urclassinstance.privilegedMethod(); ========== "); | |
urclassinstance.privilegedMethod(); | |
console.log(" ========== END OF urclassinstance.privilegedMethod(); ========== "); | |
console.log(UrClass.prototype); // { constructor: ..., method1: ..., method2: ..., ...} | |
// ============= | |
// JS lib template | |
/* | |
(function (root, factory) { | |
if (typeof define === 'function' && define.amd) { | |
// AMD, register as an anonymous module | |
define(factory); | |
} else if (typeof exports === 'object') { | |
// CommonJS | |
module.exports = factory(); | |
} else { | |
// Browser | |
root.UrClass = factory(); | |
} | |
}(this, function () { | |
'use strict'; | |
function UrClass(arg1, arg2) { | |
var _privateVarInConstructor = "private var in constructor"; | |
this.publicVar = "public var"; | |
// ES5 constructor function's privileged method has | |
// only one privilege comparing to normal public method: to access _privateVarInClass | |
this.privilegedMethod = function() { | |
} | |
} | |
var _privateVarInClass = "private var in class"; | |
var _privateMethod = function() { | |
}; | |
// normal public method, to be called with urclassinstance.method1(); | |
UrClass.prototype.method1 = function() { | |
}; | |
// static public method, to be called only with UrClass.staticMethod1(); | |
UrClass.staticMethod1 = function staticMethod1() { | |
}; | |
return UrClass; | |
})); | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment