Are these interchangeable syntaxes to create a JS class? I'm used to the class
syntax but don't understand the differences between them exactly.
function User(name) {
this.name = name;
}
User.prototype.sayHi = function() {
alert(this.name);
}
let user = new User("John");
user.sayHi();
vs.
class User {
constructor(name) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
let user = new User("John");
user.sayHi();
In object-oriented programming, a class is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods). Wikipedia.
Unlike most other languages, JavaScript's object system is based on prototypes, not classes. Unfortunately, most JavaScript developers don't understand JavaScript's object system, or how to put it to best use.
Every object in JavaScript has a built-in property, which is called its prototype. The prototype is itself an object, so the prototype will have its own prototype, making what's called a prototype chain. The chain ends when we reach a prototype that has null for its own prototype.
Prototype-based programming is a style of object-oriented programming in which classes are not explicitly defined, but rather derived by adding properties and methods to an instance of another class or, less frequently, adding them to an empty object.
The main differences between classes and constructor functions are:
Classes can’t be called without new
, but functions intended as constructors can (and their this
will be wrong)
'use strict';
function Foo() {
console.log(this);
}
class Bar {
constructor() {
console.log(this);
}
}
Foo();
Bar();
Classes can extend more types than constructors can (like functions and arrays)
'use strict';
function Foo(body) {
Function.call(this, body);
}
Object.setPrototypeOf(Foo, Function);
Foo.prototype = Object.create(Function.prototype);
class Bar extends Function {}
(new Bar('console.log(1)'))();
(new Foo('console.log(1)'))();
Classes’ prototypes are their parents (they inherit static properties); writers of constructor functions usually don’t bother with this
Non-classes can’t extend classes (because they can’t call the parent constructor – see the first point)
'use strict';
class Bar extends Function {}
function Foo() {
Bar.call(this);
}
Object.setPrototypeOf(Foo, Bar);
Foo.prototype = Object.create(Bar.prototype);
void new Foo();
Classes are also scoped like let
/const
(block scope, temporal dead zone, not redeclareable) rather than like var
(function scope, hoisted) or like function declarations (it’s complicated).
In your example, an additional difference is that sayHi
is defined by assigning to a new property instead of with e.g. Object.defineProperty
, so the property’s properties differ from those in the class example in that sayHi
is enumerable in the former but not the latter.
function UserA(name) {
this.name = name;
}
UserA.prototype.sayHi = function () {
alert(this.name);
};
class UserB {
constructor(name) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
let a = [];
let b = [];
for (let key in new UserA()) a.push(key);
for (let key in new UserB()) b.push(key);
console.log(a, b);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With