Why can't class methods call other class methods or themselves? - javascript

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?

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))

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.

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.

Related

Pattern for JS/ECMAScript6 private fields with let?

I'm new to JS, so I'm trying to find a good pattern for having private fields with ECMAScript 6.
I'm using ES6's classes running on Node.js (latest version). I came up with the following snippet but I don't understand why a variable declared with let (which in my probably-incorrect-understanding has only block scope in ES6) will survive after the block has been executed:
class PrivateTest {
constructor(aNumber) {
let _aNumber = aNumber;
//Privileged setter/getter with access to private _number:
this.aNumber = function(value) {
if (value !== undefined && (typeof value === typeof _aNumber)) {
_aNumber = value;
}
else {
return _aNumber;
}
}
}
}
const privateTest = new PrivateTest(99);
console.log(privateTest.aNumber());
privateTest.aNumber(86);
console.log(privateTest.aNumber());
console.log(privateTest._aNumber); //Undefined.
// Just to try inheritance:
class PrivateTest2 extends PrivateTest {
}
const privateTest2 = new PrivateTest2(13);
console.log(privateTest2.aNumber());
The output is this:
99
86
undefined
13
From the code above, it seems that this private field can even be inherited.
So the questions are:
Am I doing right?
What's the life cycle of _number supposed to be?
Your _aNumber (declared with let _aNumber = aNumber) doesn't exist outside of the class scope. You would get undefined if you tried to do console.log(_aNumber).
But JavaScript has something called closures that "freeze" variables inside of functions. This means that when you call the aNumber method of your class, the let variables still exist within that function.
Also, because JavaScript functions are first-class, assigning this.aNumber to a value is exactly equivalent to assigning this.aNumber to a function that returns a value, and then calling that function.
E.g.,
let a = 'foo';
let b = function() {
return 'foo';
};
b();
console.log(a); // foo
console.log(b); // foo
It's tough to say if you are "doing it right", as I'm not exactly sure what you are going for. But learning more about closures and first-class functions might help you have a better grasp on the lifecycle of variables and the nature of variable assignments.

What are the usage scenarios or advantages of defining functions after the return expression

En example can be found in Twitter'a typeahead.js here:
function () {
// ...
return this.each(initialize);
function initialize() {
// ...
}
}
Questions:
What are the scopes and what function sees what?
What is the reason for using such a construct (usage scenarios and advantages)?
Javascript has function based scope, which means that every thing defined inside a function is available from the first line, since the definition is "hoisted" by the complier.
That goes for both variable and function definitions - variable values however, are not available until after assignment.
You can read all about javascript scoping and hoisting here
This means that the function initialize is available from the first line of the wrapping anonymous function.
There is no real reason, and no advantages, for doing it that way, unless you count the code structure as an advantage.
Personally I don't see any reason to do this. For me even it looks a little bit weird. Martin is right. You should be careful, because the defined variables are not accessible like functions. For example this doesn't work:
var getValue = function(func) {
return func();
}
var f = function() {
return getValue(now);
var now = function() {
return 10;
}
}
alert(f());
However, this works:
var getValue = function(func) {
return func();
}
var f = function() {
return getValue(now);
function now() {
return 10;
}
}
alert(f());

Javascript - using arguments for closure, bad or good?

Let's consider simple singleton implementation:
var singleton = function (Constructor) {
var singleton;
return function () {
if (!singleton) {
singleton = new Constructor();
}
return singleton;
};
};
We could move declaration of singleton variable to arguments:
var singleton = function (Constructor, singleton) {
return function () {
if (!singleton) {
singleton = new Constructor();
}
return singleton;
};
};
So I simply curious about side effects.
One more example:
var counter = (function (i) {
return function () {
i = (i || 0) + 1;
return i;
};
}());
We could move declaration of singleton variable to arguments
First, let's make it possible to talk about this without tying outselves up in knots by using the same symbol (singleton) for two completely different things within the same few lines of code.
Here's your seecond example renamed:
var singleton = function (Constructor, instance) {
return function () {
if (!instance) {
instance = new Constructor();
}
return instance;
};
};
If you did that, then calling the singleton function with two arguments would specify instance, making passing Constructor in pointless — Constructor would never be called by singleton (again, if you passed in two args [and the second arg was truthy]). So it would be a bit odd to do that.
But you asked about side-effects. There are no external effects involved if you assign to a formal argument within the function. It doesn't, for instance, have any effect outside the function:
function foo(arg) {
arg = 67;
}
var a = 42;
foo(a);
console.log(a); // Still 42
However, assigning to an argument rather than to a local variable does, in non-strict mode, have a small cost, because there's overhead involved: It relates to the magic arguments pseudo-array. In non-strict mode, there's a link between the formal arguments of a function and the arguments pseudo-array:
function foo(a, b) {
console.log(a);
console.log(b);
b = 42;
console.log(arguments[1]);
}
If we call that like this:
foo(1, 2);
we see
1
2
42
Note the magic: Assigning to the formal argument b updated the pseudo-array arguments. (It works the other way, too.) That link has a small but real runtime cost.
(In strict mode, there is no link, for this very reason.)
As far as closure goes, there is no difference in the two implementations. However, in first example, singleton is not settable by the caller.
I will choose between the two implementation, just based on whether singleton could have been created outside these example functions or not. If it can be, use model 2 otherwise use model 1

Any way to get the currently executing function object in javascript?

Is there any way to refer to the function object that you're currently executing in? If it's not a method of any object or not called with .call() or .apply(), the this pointer is likely just window, not the function object.
I often use a design pattern like this for global variables that I want scoped to a particular function as this keeps them out of the top level namespace:
function generateRandom() {
if (!generateRandom.prevNums) {
generateRandom.prevNums = {}; // generateRandom.prevNums is a global variable
}
var random;
do {
random = Math.floor((Math.random() * (99999999 - 10000000 + 1)) + 10000000);
} while (generateRandom.prevNums[random])
generateRandom.prevNums[random] = true;
return(random.toString());
}
But, I'd rather not have to spell out the function name every time I want to use a variable scoped to that object. If the name of the function ever changes, there are then a lot of places to change the name.
Is there any way to get the currently executing function object?
Well, you could use arguments.callee()...
https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments/callee
From MDN:
Description
callee is a property of the arguments object. It can be used to refer
to the currently executing function inside the function body of that
function. This is for example useful when you don't know the name of
this function, which is for example the case with anonymous functions.
Note: You should avoid using arguments.callee() and just give every
function (expression) a name.
BUT...
What you really want are Javascript Prototypes.
function RandomSomethingGenerator()
{
this.prevNums = {};
}
RandomSomethingGenerator.prototype.generate = function() {
var random;
do {
random = Math.floor((Math.random() * (99999999 - 10000000 + 1)) + 10000000);
} while (this.prevNums[random])
this.prevNums[random] = true;
return(random.toString());
};
Why do I say this?
1.) You're dirtying the global space with all those functions.
2.) Even if you like Jani's suggestion, and you want a "static" function like you have now, my suggestion would be the same, but with a twist: Create your global function, and wrap an instance of an object (built from a prototype) inside the closure and make the call to it (so, basically, make yourself a singleton).
As in this (adapted from Jani's answer):
var randomSomething = (function() {
var randomSomethingGenerator = new RandomSomethingGenerator();
return function() {
randomSomethingGenerator.generate();
};
})();
I don't think there's any way to do exactly what you ask, but you could use a closure for your function-local static variables instead.
You can easily achieve this using an IIFE:
var generateRandom = (function() {
//any function's static variables go here
var prevNums = {};
return function() {
//function code goes here
var random;
do {
random = Math....
}
prevNums[random] = true;
return random.toString();
};
})();
You want arguments.callee. From MDN - callee:
callee is a property of the arguments object. It can be used to refer to the currently executing function inside the function body of that function. This is for example useful when you don't know the name of this function, which is for example the case with anonymous functions.
For example:
> foo = function() { console.log(arguments.callee); };
> bar = function() { foo() };
> bar();
function () { console.log(arguments.callee) }
However, I think this is being deprecated. The above link says, "The 5th edition of ECMAScript forbids use of arguments.callee() in strict mode."

How can I create inherited properties of functions without modifying the global Function.prototype?

Something like this works for the global Function.prototype.
Function.prototype.aaa = 1
(function () {}).aaa // => 1
But is there a way to put inherited properties of functions without changing Function.prototype?
function MyFunction () { return function () {} }
MyFunction.prototype.bbb = 2
// Can I have (new MyFunction).bbb ?
Your only other choice is to create your own Function factory function, since you've ruled out modifying the mechanism used by the standard Function factory. And of course, that's unlikely to do what you want it to do, since everyone would have to use your factory. :-)
Modifying the Function.prototype isn't necessarily evil. Prototype's been doing it for years, mostly to good effect.
function Wrap() {
var f = new Function;
/* for (var k in Wrap.prototype) {
f[k] = Wrap.prototype[k];
}
return f; */
// return $.extend(f, Wrap.prototype);
return _.extend(f, Wrap.prototype);
}
Wrap.prototype.foo = 42;
(Wrap()).foo === 42; // true
Create a new function then extend that function with properties from your Wrap.prototype.
Either use jQuery, underscore or a simple for loop.

Categories