When I define a function as following I'm able to retrieve the name of the function and no of parameters.
let func = function(arg1, arg2){
console.log("I am a function");
}
console.log("Function name : " + func.name);
console.log("No of parameters : " + func.length);
But if I use another function to retrieve a anonymous function in a variable then the function name is displayed as empty string.
let func = function(){
return function(arg1, arg2, arg3){
console.log("Nested anonymous function");
};
}
let func1 = func();
console.log("Function name : " + func1.name); // "func1" expected
console.log("No of parameters : " + func1.length);
So my doubt is in both the cases anonymous functions are getting assigned to some variable. But in first case it abopts variable's name as function's name. But in second case it doesn't. What is the reason of this peculiar behaviour?
Variables and methods can infer the name of an anonymous function from
its syntactic position (new in ECMAScript 2015).
let f = function() {};
let object = {
someMethod: function() {}
};
console.log(f.name); // "f"
console.log(object.someMethod.name); // "someMethod"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Inferred_function_names
Note the highlight: a name can be inferred from its syntactic position. Meaning, if the function appears in the source code with a left-hand side expression that lets the engine infer a name, it will do so. However, in your case the left-hand side is return, which does not allow to infer any name. Javascript will not track it through being returned from the function and assigned somewhere in the caller, so your anonymous function remains anonymous.
Here's an experiment that supplements your theory. if you name the function being returned by func, func1.name is set to that name. I think it's safe to conclude that function names are only set when initialising the function with the function ...() { ... } syntax
let func = function(){
return function func1(arg1, arg2, arg3){
console.log("Nested anonymous function");
};
}
let func1 = func();
console.log("Function name : " + func1.name); // "func1" set
console.log("No of parameters : " + func1.length);
Related
In the JS manual I have the following example, that is working correctly:
let worker = {
someMethod() {
return 1;
},
slow(x) {
alert("Called with " + x);
return x * this.someMethod(); // (*)
}
};
function cachingDecorator(func) {
let cache = new Map();
return function(x) {
if (cache.has(x)) {
return cache.get(x);
}
let result = func.call(this, x); // теперь 'this' передаётся правильно
cache.set(x, result);
return result;
};
}
worker.slow = cachingDecorator(worker.slow); // теперь сделаем её кеширующей
alert( worker.slow(2) ); // работает
alert( worker.slow(2) ); // работает, не вызывая первоначальную функцию (кешируется)
The question is: how the "this" reference is transferred into cachingDecorator function, if the cachingDecorator is not declared inside of the object, and is called like worker.slow = cachingDecorator(worker.slow)? I talk about this row inside the cachingDecorator: let result = func.call(this, x).
this reference is transferred in the last 2 rows when the decorator is actually used as worker object is before the dot.
The this is not actually in cachingDecorator, but is rather in the anonymous function being returned. So the this value is not set until that function is invoked.
Because that function is assigned to worker.slow, and you're calling it from that object, the this value gets set to the worker object.
The important thing to remember is that this is kind of like a weird function parameter. It just has a keyword for a name and always gets set (except in arrow functions). It gets set based on how the function is invoked, instead of being set like regular parameters via arguments being passed.
Note that the function cachingDecorator returns a function declared like function(x) {. . .}. Any function like this will inherit context when it is invoked as a reference to an object member:
function magicFn() { return this }
const x = { magicFn };
const y = { someKey: 6, magicFn };
x.magicFn(); // === x, because it was invoked as x.magicFn
y.magicFn(); // === y
magicFn(); // === undefined, no `this` object member reference
So when worker.slow = cachingDecorator(worker.slow) is called, the resulting function invokes the original worker.slow using worker.slow.call(this, x); which proxies the incoming this value (in this case, worker).
I wrote the following code, where I would expect the calls to getFull() and useGetFull() to do the same thing, since useGetFull just gets a function object for getFull() and calls it.
function Person(name, family) {
this.name = name;
this.family = family;
}
Person.prototype.getFull = function() {
console.log(this.name + " " + this.family);
};
Person.prototype.useGetFull = function() {
const f = this.getFull;
f();
// f.call(this) works as expected
}
p = new Person("Bob", "Smith");
p.getFull();
p.useGetFull();
However, they don't do the same thing, because inside useGetFull(), "this" is the global object. I noticed that using f.call(this) instead of f() works as intended, but I can't wrap my head around why I have to use it. Why is the value of "this" different depending on how/where I call the function?
A simple rule:
a.b() //b called with context a
d.e() //e called with context d
c() // c called with no context ( so the global instead)
Javascripts context depends on how the function was called.
If you haven't noticed, this.getFull() also works. This is because when you invoke the function as a property of an object (any object), that function's this will refer to that object, the object you invoked the function on, in case of foo.bar(), foo, and in case of this.getFull(), this. This is why this example works as expected:
function Person(name, family) {
this.name = name;
this.family = family;
}
Person.prototype.getFull = function() {
console.log(this.name + " " + this.family);
};
Person.prototype.useGetFull = function() {
/* getFull is preceded by something, it is invoked through "this", so
the "this" reference inside of getFull will be set to the "this" part in
the statement "this.getFull()". */
this.getFull();
}
p = new Person("Bob", "Smith");
p.getFull(); prints out Bob Smith
p.useGetFull(); // prints out Bob Smith
However, when a function is invoked not as the property on an object, in other words, when it is not accessed in a way similar to either foo.bar() or foo["bar"](), but in a way like foo(), even if foo is a reference to a variable whose value is x.y, like f() in your example, its this will be bound to the global object, in a browser, that object is window.
function Person(name, family) {
this.name = name;
this.family = family;
}
Person.prototype.getFull = function() {
console.log(this.name + " " + this.family);
};
Person.prototype.useGetFull = function() {
const f = this.getFull;
/* this call is not preceded by any objects, it is a plain
traditional function call, it is a function invokation in its
simplest form. all functions invoked in this manner will have
their "this" reference set to the global object. */
f();
}
p = new Person("Bob", "Smith");
p.getFull();
p.useGetFull();
If you are interested in this (pun not intended), go here.
So I'm learning Javascript and I see this code:
var apple = {//... an object with some properties};
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple});
Where someMethod and a_property_of_apple are valid methods and properties.
My question pertains to the argument, b, of the anonymous function which is not declared or defined anywhere else:
function (b) {return ...
What is going on here? What is b and why is it being used?
Apologies in advance for the basic nature of the question. If someone just wants to drop some focused terms on me to read up on that would be great short of an explanation.
The anonymous function is a callback function being passed to the apple.method() invocation.
apple.method() will invoke that anonymous function at some point during it's execution, ( or pass it to another function ). Whenever it's invoked it will be invoked with an argument that will be available inside the callback. You could call it b, or response, or whatever you want (logical names are best) and be able to use it within the anonymous function.
You should read about Callback functions over at MDN.
EDIT: I will explain the parts to you
var apple = {} This is the definition of an object
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple}); is defining that fruit is equal to the return value of the invocation of apple.someMethod(...)
apple.someMethod(function (b) {return b.a_property_of_apple}); is the invocation of apple.someMethod with function (b) {return b.a_property_of_apple} as the only argument.
The b argument in the anonymous function function (b) {return b.a_property_of_apple} will be passed to it's invocation within the apple.someMethod.
Here is an example snippet.
// define apple
var apple = {
// define method
someMethod: function( callback ) {
var obj = {
a_property_of_apple: "Eat me!" // this will be returned
}
// return the invocation of callback with obj as argument
return callback(obj);
}
}
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple});
console.log(fruit);
EDIT: Ok, going to use something slightly less abstract as an example.
// notice employees being passed to this function
// that is called an argument and is usable inside the function
var orginization = function( employees ) {
// this will take the empoyees argument and assign it to this.employees
// or set this.employees to an empty array if there is no employees argument
this.employees = employees || [ ];
// this is a method ( a method is a function on an object )
// this function takes 3 arguments
this.addEmployee = function( employee ) {
// we use the 3 arguments to push a new object with title, name, and salary
// properties provided by the function arguments
this.employees.push( employee );
}
// this method returns the value stored in this.employees
this.getEmployees = function() {
return this.employees;
}
}
// this is a variable an array of employees only containing 1 employee
// i will use it in the creation of my new orginization
var employess = [
{
title: "CEO",
name: "Enola",
salary: "$$$$$$$"
}
];
// i use the new to create learningInc from originization( employees )
// originization is a constructor function which creates an object
// with methods and properties found on the constructor
var learningInc = new orginization( employess );
// console.log learningInc.getEmployees() an you will see still only the CEO
// works here
console.log( "before newHire: ", learningInc.getEmployees() );
// lets make a newHire
var newHire = {
title: "Peon",
name: "Sadly McFrownFace",
salary: "$"
};
// add the newHire to the employess of learningInc wth out getEmployees() method
learningInc.addEmployee( newHire );
// log the new value of learningInc.getEmployees and you see we now have 2 employees
console.log( "after newHire: ", learningInc.getEmployees() );
Ok now notice this line var learningInc = new orginization( employess );
The employees variable I'm passing to this function as an argument is used in this function var orginization = function( employees ) { ... }.
Hope this help.
My question pertains to the parameter, b, of the anonymous function which is not declared or defined anywhere else: What is going on here?
What is b and why is it being used?
Why you say it is not declared? It is declared right there. Consider this simple JavaScript function:
function doSomething(a, b){
//do something here;
}
In this code, we are creating a function, naming it "doSomething", and declaring two parameters for it a and b. This is how we declare function parameters in JavaScript. Now your example:
function (b) {return ...
is exactly the same, except we didn't give this function a name, which means it is an anonymous function. That's the only difference, but its parameter b is declared right there like any standard function. So there is nothing special going here, it's a standard function parameter and used as such.
There are a couple concepts at work here
Function declarations vs function expressions; you can use function as an operator to define a function, and assign the function to an identifier and pass it around like any normal object
Callbacks; you can pass a function CB into another function A to be called by A (as defined by A)
Passing something without an identifier
Function Declaration
// declare function
function foo(argFoo) {
console.log('foo', argFoo);
}
// invoke function
foo('was declared'); // "foo" "was declared"
Function Expression
// express function
var bar = function (argBar) {
console.log('bar', argBar);
};
// invoke function
bar('was expressed'); // "bar" "was expressed"
Callbacks
function fizz(callback) {
console.log('first I fizz');
callback();
}
function buzz() {
console.log('then I buzz');
}
fizz(buzz);
// "first I fizz"
// "then I buzz"
Passing without an Identifier,
Basically, defining things in-place
// say we have some fn fizzbuzz
function fizzbuzz(foo) {
console.log(foo);
}
// we could pre-define what we want to pass to it
var i = 1;
fizzbuzz(i); // 1
// or we could pass directly
fizzbuzz(1); // 1
// with anything we like
fizzbuzz({some: 'object'}); // {some: "object"}
// even a function
fizzbuzz(function () {}); // function () {}
Maybe if I break down what is happening into more readable code, you can see what is happening.
someMethod is a method that take a function as an argument. This is more easily seen when broken down like below.
It's up to someMethod to determine what they do with that function. In this example, I am executing the function being passed into someMethod and passing it my this context.
var apple = {
name: 'Apple',
someMethod: function(func) {
return func(this);
}
};
function getName (b) {
return b.name;
};
const name = apple.someMethod(getName); // Apple
To your question: b is defined as the first argument to your anonymous function. This is more clearly expressed when the code is broken out above. But you could also express it like this:
const name = apple.someMethod(function(x) { return x.name; }); // Apple
or like this using ES6:
const name = apple.someMethod(x => x.name); // Apple
function Car(make, model) {
this.make = make
this.model = model
console.log(" Iam inside the object" )
this.whatsmymodel = function () {
console.log(" Iam " , this.model)
}
function whatsmymake() {
console.log(" Iam " , this.make)
}
}
function whatsthis() {
console.log (" This is a function")
}
Car.prototype.whoami = function () {
console.log(" Iam " , this.make + " " + this.model)
}
var tesla = new Car("Tesla", "ModelS")
tesla.whoami()
tesla.whatsmymodel()
tesla.whatsmymake() // Error!!
whatsthis()
How come I get error for tesla.whatsmymake()
TypeError: tesla.whatsmymake is not a function
I understand it is possible in the new ES6 class but wouldnt it be easier to define a function within a function constructor ?
It is letting me define but doesnt allow me to call - why is that ?
You have defined a function called whatsmymake inside the lexical scope of the Car constructor, but you have not done anything to create a property call whatsmymake on the this returned by the Car constructor. If every function defined inside the lexical scope of a constructor were attached to the constructed object, this would be very inconvenient, and would disallow the creation of helper methods inside the constructor without also attaching those helper methods to the constructed object. For example:
function Car() {
this.rightWheelAngle = 0;
this.leftWheelAngle = 0;
this.turnLeft = function() { turnBothWheels(1); }
this.turnRight = function() { turnBothWheels(-1); }
function turnBothWheels(inc) {
this.rightWheelAngle += inc;
this.leftWheelAngle += inc;
}
}
Suppose we do not want to expose turnBothWheels as a method on the returned object. JavaScript does not require you to do so, but you can still use the turnBothWheels function within functions that have lexical-scope visibility of that function (such as the turnRight and turnLeft methods, above).
As for why function declarations don't allow a property-access name-path like function foo.bar.baz() { ... }, they just don't -- function names must be plain identifiers. That's how the grammar is defined. If you want to have a function in a property named baz on the object stored in the property bar on the object foo, then simply do an assignment to store it there: foo.bar.baz = function() { ... }
I've created a function and bound the arguments as below.
function myFunc(){}
let boundFunc = myFunc.bind(argument);
But then I pass this bound function as an argument to another function, where I need to get the name. The following:
function doTheThing(callable){
console.log(callable.name + " did the thing");
}
doTheThing(boundFunc);
Prints out bound did the thing rather than myFunc did the thing. Is there any way to get the name of the bound function?
callable.caller results in Uncaught TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context. and is not browser standard.
Google Chrome v 51.0.2704.103 gives a different result:
function myFunc(){}
let boundFunc = myFunc.bind(null);
function doTheThing(callable){
console.log(callable.name + " did the thing");
}
doTheThing(boundFunc);
It prints bound myFunc did the thing, so you could get the original name with callable.name.substring(6)
Long story short callable.name does work, and produces bound myFunc.
My version wasn't working because I was using transpiled typescript. This snippet:
class MyClass{
static doTheThing(callable) {}
}
let myFunc = MyClass.doTheThing.bind(null);
function handleCall(callable){
console.log(callable.name)
}
handleCall(myFunc);
produces:
var MyClass = (function () {
function MyClass() {
}
MyClass.doTheThing = function (callable) {};
return MyClass;
}());
var myFunc = MyClass.doTheThing.bind(null);
function handleCall(callable) {
console.log(callable.name);
}
handleCall(myFunc);
The key is the line MyClass.doTheThing = function (callable) {}; This makes MyClass.doTheThing an anonymous function therefore returning undefined for it's name. This results in callable.name returning "bound " + undefined or "bound ".
So in short, you can get the name of a bound function, but a girl function does not have a name.
If you're using node (tested now on v9.2.0), try
import util from 'util'
function myFunc(){}
let boundFunc = myFunc.bind(null)
let functionInfo = util.format(boundFunc)
console.log(functionInfo) // [Function: bound myFunc]
.. and extract it from there