Reputation: 6196
I am curious why methods cannot call other methods or themselves in javascript. For example, this produces a Reference error saying add is not defined.
class sum {
add(x, amt) {
if(amt == 0) return x
return add(x+1, amt-1)
}
}
summer = new sum()
console.log(summer.add(5,5))
You must use this.add() instead.
Now I understand that the methods get translated to functions on the prototype but I don't see how that explains this limitation I'm pointing out?
Couldn't one reason that when add is defined it could have references to itself or other methods with a closure capture.
Why is it this way?
Upvotes: 4
Views: 1956
Reputation: 7446
I will try to make it "slightly" more theorical, without going too deep in the documentations and so on.
The main answer to your question can be found by transpiling your code to plain javascript. To accomplish that, you can either use babel online or the typescript online playground. Either case, the transpiled code will look like this:
"use strict";
var sum = /** @class */ (function () {
function sum() {
}
sum.prototype.add = function (x, amt) {
if (amt == 0)
return x;
return add(x + 1, amt - 1);
};
return sum;
}());
var summer = new sum();
console.log(summer.add(5, 5));
As you can see, the add
method belongs to the sum prototype, which is a function. Therefore, you can guess that accessing add
whithin the add
scope just can't implicitly lead to invoking the sum.prototype.add
function.
Differently, if you look at the correct code:
class sum {
add(x, amt) {
if(amt == 0) return x
return this.add(x+1, amt-1)
}
}
var summer = new sum()
console.log(summer.add(5,5))
You will see that the transpiled code will invoke the this
method:
"use strict";
var sum = /** @class */ (function () {
function sum() {
}
sum.prototype.add = function (x, amt) {
if (amt == 0)
return x;
return this.add(x + 1, amt - 1);
};
return sum;
}());
var summer = new sum();
console.log(summer.add(5, 5));
This is not really matter of being ambiguous, it's rather that, in javascript, such kind of invocation is allowed, because the add
method is implicitly available from the global scope. Being able to access the global scope in your function scope (because remember that, whatever happens, a class
in javascript is always transpiled to a function) allows to inherit the standard behavior of a function, which is having access to its parent, having its own scope and granting access to the global scope.
A little curiosity: if you actually could access this.add
using add
, you wouldn't be able to use undefined
, since it's a global variable, hence you wouldn't be able to access it and use it, because it would implicitly be this.undefined
.
So, once again, it's not about ambiguity, it's about how javascript functions works.
Upvotes: 2
Reputation: 522042
Fundamentally OOP in Javascript is very different to java and other languages. There's not actually a strong concept of "classes". The classic OOP concepts like classes and instances in Javascript don't really come from "classes", but from the rules surrounding property lookups and the this
and new
keywords. Everything else is just functions, objects and properties—some of which are "special", like prototype
.
E.g. you can assemble a "class" like this:
function Foo() {
this.bar = 42;
}
function baz() {
return this.bar;
}
Foo.prototype.baz = baz;
let foo = new Foo;
console.log(foo.baz());
There's no real cohesion here, baz
doesn't intrinsically belong to any class, yet assembled like this they act like one. And the class
syntax is just a thin veneer over this mechanism. So, if you write add
inside a function, it follows variable scoping rules and will look up a variable in some surrounding scope, it's not going to find a method on a prototype.
Upvotes: 0
Reputation: 55623
I was in the middle of illustrating this shortcoming when @briosheje made the comment:
function add() {
console.log('called the wrong add!');
}
class sum {
add(x, amt) {
if(amt == 0) return x
return add(x+1, amt-1)
}
}
summer = new sum()
console.log(summer.add(5,5))
Upvotes: 3