Javascript: What's the difference between .call() and super()? - javascript

What's the difference between .call() and super()? Is super() just an es2015 thing? Or does .call() have more functionality?

super() calls the constructor of the class you extened
class Foo extends Bar {
constructor() {
super(); // calls Bar's constructor
}
}
call is a generic function you can use with any function
function a() { console.log(this); };
function b() { console.log(this); };
function c() { console.log(this}; };
a.call("hello");
b.call(123);
c.call({});
super knows which class you inherited from and automatically passes the correct this.
class Foo extends Bar {
constructor() {
super(); // calls Bar's constructor
}
}
call requires you to be explicit.
class Foo extends Bar {
constructor() {
Bar.call(this); // You had explicitly specify 'Bar'
// and explicitly pass 'this'
}
}
super lets you call functions on the parent implicitly
class Bar {
log() {
console.log("bar-log");
}
}
class Foo extends Bar {
log() {
super.log();
}
}
call requires you to be explicit
class Bar {
log() {
console.log("bar-log");
}
}
class Foo extends Bar {
log() {
Bar.prototype.log.call(this); // Explicitly reference bar's log function
// and explicitly specify 'this'
}
}
I think you could argue super offers a subset of the functionality of call. Some might call it syntactic sugar meaning you can use call everywhere you can use super, super is just easier because it implicitly calls stuff from the class you extended/inherited from (technically the next thing up the prototype chain?) and because it implicitly passes this for you.

I imagine you relate call and super because of code like the following:
function Foo() {
Bar.call(this)
}
class Foo extends Bar {
constructor() {
super()
}
}
In the case above, both examples do the same thing (call the constructor of Bar in the context of a new instance of Foo), but from there super and call differ greatly.
First off super is a key word, call is a method of Function's prototype.
The super keyword can be used to call the parent classes constructor and methods. So, in addition to the examples above super can do this:
class Bar {
constructor() {
//...
}
bang() {
console.log('bang')
}
}
class Foo extends Bar {
constructor() {
super()
//...
}
bang() {
// call parents method in context of `this`
super.bang()
//...
}
}
call, on the other hand, is a method of the Function class that allows a function to be invoked with an explicit value for the this variable. Consider the following function.
function baz() { console.log(this.bar) }
baz() // -> "undefined"
baz.call({ bar: 'foo' }) // -> "foo"
The above example is actually a little more nuanced. Unless in strict mode, this will be the global object (global, window). In strict mode, this is undefined, and our baz function will throw an error. With call we can explicitly set this, a very powerful feature.

Related

ReactJs Events Binds [duplicate]

In new React ES6 classes this needs to be binded as stated here: http://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding
for eg:
class Counter extends React.Component {
constructor() {
super();
this.tick = this.tick.bind(this);
}
tick() {
...
}
...
}
The explanation for this is because it's the default behaviour, however if I make an ES6 class and then I make a new instance of it this will be binded
import React from 'React'
class Test extends React.Component {
constructor() {
super()
}
foo () {
console.log('bar')
}
hello() {
this.foo()
}
}
var test = new Test()
test.hello()
// > bar
Why binding is needed in React then?
You need set this to methods in case, for example, if you need pass function reference to event handlers, however you don't need set this for every method.,
class Counter extends React.Component {
constructor() {
super();
this.tick = this.tick.bind(this);
}
tick() {
// this refers to Counter
}
fn() {
// this refers to Counter
}
withoutBind() {
// this will be undefined or window it depends if you use "strict mode" or not
}
render() {
this.fn(); // this inside this method refers to Counter
// but if you will do like this
const fn = this.fn;
fn(); // this will refer to global scope
return <div>
<button onClick={this.tick}>1</button>
<button onClick={this.withoutBind}>2</button>
</div>;
}
}
Example
Classes in ES6 are functions. When you instantiate a class, you get an object. For all the methods in your class, if you used this inside them, it refers to the object that owns the method.
But it is confusing when you extract the method because the context changes. Examples:
let foo = Counter()
foo.tick()
If you call foo.tick(), this belongs to the object foo. Cool.
But watch this:
tickFunc = foo.tick()
tickFunc()
You detached the function from the original object, now the function invocation happens where this inside tickFunc() refers to the global object.
So why do you need to bind your methods in React? You do it because most of the times we are passing the method references either to the event handlers or as props to components. When you pass references of your methods, they become detached functions and their context changes. To solve that, you use bind() in the constructor.

How to refer the current class inside it's static method? [duplicate]

How can I refer to a class from a static method without using the class name itself in JavaScript (similar to PHP's self and self::method_name)?
For example, in the class below, how can I refer to the method foo and the method bar inside of the foobar method without the use of FooBar.methodName?
class FooBar {
static foo() {
return 'foo';
}
static bar() {
return 'bar';
}
static foobar() {
return FooBar.foo() + FooBar.bar();
// self::foo() + self::bar() would have been more desirable.
}
}
You can use the this keyword to refer to the object itself.
See example below:
class FooBar {
static foo() {
return 'foo';
}
static bar() {
return 'bar';
}
static foobar() {
return this.foo() + this.bar();
// self::foo() + self::bar() would have been more desirable.
}
}
const res = FooBar.foobar();
console.log(res);
Yes: the syntax you're asking about is "this".
From MDN:
https://medium.com/#yyang0903/static-objects-static-methods-in-es6-1c026dbb8bb1
As MDN describes it, “Static methods are called without instantiating
their class and are also not callable when the class is instantiated.
Static methods are often used to create utility functions for an
application.” In other words, static methods have no access to data
stored in specific objects.
...
Note that for static methods, the this keyword references the class.
You can call a static method from another static method within the
same class with this.
Also note:
There are two ways to call static methods:
Foo.methodName()
// calling it explicitly on the Class name
// this would give you the actual static value.
this.constructor.methodName()
// calling it on the constructor property of the class
// this might change since it refers to the class of the current instance, where the static property could be overridden
If all of those methods are static then you can use this.
class FooBar {
static foo() {
return 'foo';
}
static bar() {
return 'bar';
}
static foobar() {
return this.foo() + this.bar();
}
}

How to define prototype method inside class definition (externally) in Javascript?

I have a class declaration which is quite large with lots of methods.
It's something like this:
class Foo {
constructor() {
// ...code
}
config() {
// ...code
}
theme() {
// ...code
}
register() {
// ...code
}
render() {
// ...code
}
write() {
// ...code
}
}
I'd like to split the source code up so it's easy to manage and read.
Is there a way I can assign a method to a class dynamically within the class itself?
I'd like to do something like:
function bar(value) {
if (value) {
this.baz = 'baz'
return this
}
}
class Foo {
constructor() {
// ...code
}
new bar() // Would reference function above ^ (not valid)
}
I know this is not valid or correct but because the class syntax automatically creates and binds a property called bar() to the prototype of Foo I can't think how you would do it, and perhaps the functionality doesn't exist.
The closest I can think to splitting the code up, is to extend a class but this seems a bit verbose.
class Bar {
bar() {
if (value) {
this.baz = 'baz'
return this
}
}
}
class Foo extends Bar {
constructor() {
super()
}
}
bar() is now in Foo's prototype.
This method also offers little control to creating aliases if needed and also is harder to make it clear what methods that are available in the Foo class.
Is there a better way?
I can think of two ways of adding external functions as own properties:
Set it as a property of the this inside the constructor of the class.
Set it as a public property of the class, this is the proposal.
The downside is that, all the instances will not share the same function object as it becomes an own property. Own properties are used for holding state not functions.
To add in prototype, which is where methods in ES6 class are added, so that all instances share the same function object. You have to add it to the prototype property of the class. This works as class is a syntactic sugar of the function constructor and every function has a prototype property which is inherited by all instances of that class.
class Foo {
constructor() {
// ...code
this.bar = bar; //becomes own property
}
//As a public field, becomes own property
baz = baz;
}
function bar(){
console.log("from bar");
}
function baz(){
console.log("from baz");
}
function foobar(){
console.log("from foobar");
}
const foo = new Foo();
foo.bar();
foo.baz();
//Set it directly on the prototype prop of the Class
Foo.prototype.foobar = foobar;
foo.foobar();
Also, I presume there isn't a way to set a prototype of a class inside
the class definition itself?
From your question in the comment, yes you can set the function in the prototype of the class inside the class definition itself:
function bar(){
console.log("bar in prototype");
console.log("accessing data from this: ", this.data);
}
class Foo{
constructor(){
this.data = "data"
Foo.prototype.bar = bar;
Foo.prototype.thisBar = bar.bind(this);
}
//methods are added in prototypes
baz(){
console.log("baz in prototype");
}
}
const foo = new Foo();
foo.bar();
foo.baz();
//accessing from prototype, here this is global context and will print undefined
Object.getPrototypeOf(foo).bar();
//this is bound so always refers to the instance
Object.getPrototypeOf(foo).thisBar();
//same for methods in es6
Object.getPrototypeOf(foo).baz();
For static methods just set it either as a property of the class or set it as public static property.
class Bar{
constructor(){
//some logic
}
static baz = baz;
}
function foo(){
console.log("from foo");
}
function baz(){
console.log("from baz");
}
Bar.foo = foo;
Bar.foo();
Bar.baz();

In a React Component, what's the difference between foo(){} and bar = () => {} and when should I use which?

Babel is doing its magic, which makes me very confused about what's going on.
What's the difference between foo and bar in this react Component? And when should I use which?
class MyComponent extends Component {
foo() {
//...
}
bar = () => {
//...
}
}
(My own guess is foo is in the prototype, and bar is in the constructor? Anyways, I don't know what I'm talking about)
My own guess is foo is in the prototype, and bar is in the constructor?
That's exactly right.
foo() {}
in this context is a method declaration and the value gets assigned to the prototype. It's equivalent to
MyComponent.prototype.foo = function() {};
bar = ... ;
on the other hand is a class field. This is a shorthand notation for assigning properties to the instance in the constructor:
constructor() {
this.bar = ... ;
}
And because of how arrow functions work, using class fields with arrow functions basically lets you create "bound" methods.
More on arrow functions: Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?
And when should I use which?
The tl;dr is: Use class field + arrow function when you need a bound function.
When do you need a bound function? Whenever you want this inside the function to refer to a specific value but you don't control how the function is called.
That's mostly the case for event handlers (i.e. functions that are passed to other functions / components) that need to access the component instance (e.g. call this.setState or access this.props/this.state).
You don't have to use it though, you could also bind the method when you need to. However, binding a method only once in the constructor is ideal for React components so that, if the method is passed as event handler, always the same function object is passed.
As noted in another answer, this is not related to React at all. Class fields are likely officially integrated into the language this year.
In the second example bar is an arrow function.
Until arrow functions, every new function defined its own this value.
For instance, this can be a new object in the case of a constructor.
function Person(age){
this.age=age;
console.log(this);
}
let person=new Person(22);
Or this can points to the base object if the function created can be accessed like obj.getAge().
let obj={
getAge:function(){
console.log(this);
return 22;
}
}
console.log(obj.getAge());
An arrow function does not create its own this, it's just used the this value of the enclosing execution context. In the other hand, arrow function uses this of parent scope.
foo is an instance method of class MyComponent. While bar is an instance property of class MyComponent (that happens to be assigned an anonymous function).
It might make more sense to see it used in the traditional sense...
class MyComponent {
// instance property
someProperty = 42;
// instance method
someMethod() {}
}
So why use an instance property instead of an instance method?
Instance methods in javascript must be called within the class scope to inherit the class context (this)...
class MyComponent {
// instance method
someMethod() {
const value = this.state.value // ERROR: `this` is not defined
}
render() {
return <div onClick={this.someMethod} />
}
}
However, since arrow functions inherit their scope, this will be available if you use an arrow function instead
class MyComponent {
// instance method
someProperty = () => {
const value = this.state.value // this works!
}
render() {
return <div onClick={this.someProperty} />
}
}
Essentially, there is no difference.
This has nothing to do with React, though.
Arrow functions
Arrow functions are a relatively new feature added to Javascript that give you a way of defining functions in a more concise way.
function foo (param1, param2, etc) {
// do something
}
// becomes
var foo = (param1, param2, etc) => {
// do something
}
If you have only 1 param, you don't need the parantheses:
function foo (param) {
// do something
}
// becomes
var foo = param => {
// do something
}
If there is only 1 expression, and the result is returned, you can omit the {} too!
function foo (param) {
returns param * 2
}
// becomes
var foo = param1 => param * 2
this is not not updated
In an arrow function, you don't get a new this - it is the same as in the parent block. This can be useful in some cases (when using setTimeout, for example)
JS Classes
In ES6 we can also use the class keyword to define "classes" in Javascript. They still use prototype, though!
function Something (foo) {
this.bar = foo;
}
Something.prototype.baz = function () {
return baz * 2
}
// becomes
class Something {
constructor(foo) {
this.bar = foo;
}
baz () {
return baz * 2
}
}
So the constructor is done in constructor() and all the following methods are added to the Prototype. It's nothing but syntactic sugar (but kinda does some of the Prototype heavy lifting for you)
You can use extends!
class SomethingElse extends Something {
constructor(foo, lol) {
this.lol = lol
// Use super() to call the parent's constructor
super(foo)
}
baz () {
return baz * 2
}
}

Determine if super() is called from inherited class

Is there a way to determine that the inheriting class has bothered to call super() in JavaScript?
function A() {
A.prototype.isInitialized = function() {
// what can be checked to see if B bothered to called super()
}
}
class B extends A {
//constructor() {
// didn't call super()
//}
}
Assume B didn't have its own constructor. Does it just use A's constructor thus effectively having called super by default?
Yes, no constructor is the same as a constructor that just calls super, so you don't have to worry about having an uninitialized parent.
class A {
constructor() {
this.isInit = true
}
isInitialized() {
return !!this.isInit
}
}
class B extends A {
constructor() {
super()
}
}
class C extends A {
}
b = new B()
console.log(b.isInitialized())
c = new C()
console.log(c.isInitialized())
It is not possible to create an instance of B without also calling A's constructor (except if you don't use the object that would be created for you, and return another object, see further down).
If you don't specify a constructor for class B, then silently one is created for you that looks like this (in your case there are no arguments):
constructor(...args) {
super(...args);
}
If you explicitly create a constructor for B, and don't return an object, then you must call super in it, otherwise no instance of B can be created. The following will produce an error:
function A() {
console.log('hi');
}
class B extends A {
constructor() {
// no call to super is made
}
}
var b = new B(); // Reference Error: `this` is not defined
Using return
If however, you ignore the object that would be created for you (the context, this), don't reference this, and return another object, then the constructor of the parent will not be called:
function A() {
console.log('hi');
this.isInitialised = true;
}
class B extends A {
constructor() {
return Object.create(B.prototype);
}
}
var b = new B();
console.log(b instanceof B, b instanceof A, b.isInitialised); // true, true, undefined
Here we use Object.create to create an instance of B's prototype, which is an instance of A, but A's constructor does not get executed. See the output to interpret the result.
Conclusion
So, whether you define a constructor on B or not, in all valid cases where you don't return an object, the constructor of A is called.
When using return in B's constructor, it is possible create an object that still is an instance of A, but where its constructor is not called. You can use a property in instances of A to indicate whether the constructor ran or not.

Categories

Resources