Javascript, get the name of a bound function - javascript

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

Related

How can I get the Function object in the body of such function?

Is there a way to get the Function object, while the function is executing?
I am assigning properties to my function, and want to access them. "this" doesn't help. Something like:
a.b=function(){...code...};
a.b.c=100;
I want to access a.b.c from the code in the function, without knowing its own name. "this" refers to a. How can get b?
I tried binding the function to his own object, but I couldn't.
Thank you.
I'm adding this example, I have to repeat after several different "theString" and "someSpecificValues":
Object.defineProperty(theObject, theString, {get: function(...){...}.bind(theObject, someSpecificValues), configurable: true});
You can use a named function expression for this:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.b();
It allows code inside the function to access the function itself, but does not add the identifier to the enclosing scope.
Edit: Here is a more elaborate example of how the name myFunc only exists within the function:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.d = function myFunc() {
console.log(myFunc.c);
};
a.d.c = 300;
a.b(); // logs 100
a.d(); // logs 300
console.log(typeof myFunc); // logs "undefined"
// create a myFunc variable
var myFunc = function() {
console.log("nooooooo!!!!");
};
a.b(); // STILL logs 100. the myFunc variable in this scope
// has no effect on the myFunc name that a.b uses
function callFunc(theFunc) {
theFunc();
}
callFunc(a.d); // STILL logs 300
// ===========================
function returnNamedFunction () {
return function myFunc() {
console.log(myFunc.c);
};
}
var iGotAFunction = returnNamedFunction();
iGotAFunction.c = 700;
iGotAFunction(); // logs 700
In the case when you cannot use a named function expression, e.g. when you are using .bind() on it, then an IIFE will suffice most of the time:
var myObj = {};
myObj.theFunc = (function () {
var f = function (arg1, arg2) {
console.log(this.theProp);
console.log(arg1);
console.log(arg2);
console.log(f.lista);
}.bind(myObj, "A!");
return f;
})();
myObj.theProp = "B!";
myObj.theFunc.lista = [1, 2, 3];
myObj.theFunc("C!");
There are two ways to get current function.
One is "almost deprecated" usage of arguments.callee. In function body it always refers to this function.
var a = {};
a.b = function () {
console.log(arguments.callee.c);
};
a.b.c = 100;
a.b();
arguments.callee is forbidden in strict mode. Reference.
The second one is using named function expression as JLRishe pointed.
arguments.callee pros and cons
Advantages:
it can be safely used with bound functions (arguments.callee refers to bound function)
it can be used with functions created using new Function
Disadvantages:
it can slow your program due to disabling certain optimisations
it's considered as almost deprecated
it can't be used in strict mode
Named function expression pros and cons
Advantages:
it's faster than arguments.callee
it's easier to understand how it works
Disadvantages:
it won't work as expected with bound functions (functionName will refer to original function, not bound one)
it can't be used in functions created with new Function

Javascript bind to object

function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
var func = john.says;
func();
I tried this example when I do this I get the following message undefined rocks! instead of Ruby rocks!.
can u explain why is that.
Function Execution Context and the this Keyword
JavaScript functions have an execution context at invocation time such that the this keyword is bound to the object they are invoked from. If you call john.says() the execution context of the function would have a this keyword that points to john. If you instead assign a global variable func to the method says found on the object john you have changed the execution context to the global object. When you invoke the func function, this dereferences to window (or undefined*) and since window.skill is undefined, says will coerce that value into a string to concatenate it with the string ' rocks!'.
How to guarantee execution context using bind
You can instead bind a copy of the function to an object (effectively locking it's context reference):
var func = john.says.bind(john);
How to guarantee execution context using a closure
Alternately you can close over the relevant bits by using a closure in your constructor:
function Developer(skill){
var _this = this; // we keep a reference here
this.skill = skill;
this.says = function(){
alert(_this.skill + ' rocks!');
// when invoked _this refers to the context at construction
}
return this;
}
How to guarantee a value using a closure
You could just reference the skill value directly from the method and so not need the context at all:
function Developer(skill){
// because skill is defined in this context, says will refer to this context
// to get the value of the skill variable.
this.says = function(){
alert(skill + ' rocks!');
}
}
How to guarantee an execution context at invocation time using call and apply
The final options are to to invoke the method with the context you want at invocation time:
func.call(john /*, optional arguments... */);
func.apply(john /*, optional arguments as an array */);
How to use prototypes to allow the dynamic execution context to set the right this
If we want to reuse a method between object instances or types but have the right execution context when invoked we can use the prototype property.
function Developer(skill){
this.skill = skill;
this.says();
}
Developer.prototype.says = function(){
alert(this.skill + ' rocks!');
}
var john = new Developer("Ruby"); // alert("Ruby rocks!")
var tony = new Developer("JavaScript"); // alert("JavaScript rocks!")
More reading:
Specification for execution contexts: http://ecma-international.org/ecma-262/5.1/#sec-10.3
MDN Docs about this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FOperators%2Fthis
* "use strict" activates a special strict mode representing the future of JavaScript. This special strict executing environment will not resolve to the global object when a context has not been set, instead resolving this to the appropriately scoped value undefined.
Let's illustrate what is happening, by actually returning the object:
function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
return this; //this is basically { skill: skill, says: function() {} }
}
var john = new Developer('Ruby');
var func = john.says; // all it knows is the function() part, has no knowledge of skill
func(); //undefined rocks!
Ok, so why are we getting undefined? Well, once we rip out the function, it no longer has context - it doesn't know what this is. If we were to do:
func.apply(john);
Then we are passing in John as the this parameter. A workaround, it to pass the value in to the function when we create it:
function Developer(skill) {
this.skill = skill;
this.says = function(skill) { //<--calling this function
return function() { //<--returning this function
alert(skill + ' rocks!');
};
}(this.skill); //<--passing in the value here
return this;
}
When you call a function, this will refer to the object on which the function was called.
When you say
var func = john.says;
you are just getting the function object (it doesn't remember the object on which it is defined).
When you invoke the function, like this
func();
there is no current object, on which func is invoked. So, by default, JavaScript assigns the global object(window object in browser) as this. Since, skill is not defined in the global object, undefined is returned.
Note: In Strict mode, this will be undefined, if there is no current object.
That is why we have to explicitly bind the object to the function, like this
func.bind(john)();
Function.prototype.bind will return a new function, which is bound to john. So, when you invoke this this will refer john.
Because func() only has the function and not any other related info.(this.skill)
The context is lost. this referred to the john when the says() is called.
But now, when you call func() this refers to the window. Therefore this.skills will return undefined unless you have a global variable of the same name.
the fastest way to keep the above pattern is to bind this direct to the method this.says = function () { ... }.bind(this);:
function Developer(skill) {
this.skill = skill;
this.says = function () {
alert(this.skill + ' rocks!');
}.bind(this);
}
var john = new Developer('Ruby');
var func = john.says;
func(); // Ruby rocks!
try this
function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
john.says();
working demo
http://jsfiddle.net/ZENtL/

Method vs Functions, and other questions

With respect to JS, what's the difference between the two? I know methods are associated with objects, but am confused what's the purpose of functions? How does the syntax of each of them differ?
Also, what's the difference between these 2 syntax'es:
var myFirstFunc = function(param) {
//Do something
};
and
function myFirstFunc(param) {
//Do something
};
Also, I saw somewhere that we need to do something like this before using a function:
obj.myFirstFunc = myFirstFunc;
obj.myFirstFunc("param");
Why is the first line required, and what does it do?
Sorry if these are basic questions, but I'm starting with JS and am confused.
EDIT: For the last bit of code, this is what I'm talking about:
// here we define our method using "this", before we even introduce bob
var setAge = function (newAge) {
this.age = newAge;
};
// now we make bob
var bob = new Object();
bob.age = 30;
// and down here we just use the method we already made
bob.setAge = setAge;
To answer your title question as to what is the difference between a 'function' and a 'method'.
It's semantics and has to do with what you are trying to express.
In JavaScript every function is an object. An object is a collection of key:value pairs. If a value is a primitive (number, string, boolean), or another object, the value is considered a property. If a value is a function, it is called a 'method'.
Within the scope of an object, a function is referred to as a method of that object. It is invoked from the object namespace MyObj.theMethod(). Since we said that a function is an object, a function within a function can be considered a method of that function.
You could say things like “I am going to use the save method of my object.” And "This save method accepts a function as a parameter.” But you generally wouldn't say that a function accepts a method as a parameter.
Btw, the book JavaScript Patterns by Stoyan Stefanov covers your questions in detail, and I highly recommend it if you really want to understand the language. Here's a quote from the book on this subject:
So it could happen that a function A, being an object, has properties and methods, one of which happens to be another function B. Then B can accept a function C as an argument and, when executed, can return another function D.
There is a slight difference -
Method : Method is a function when object is associated with it.
var obj = {
name : "John snow",
work : function someFun(paramA, paramB) {
// some code..
}
Function : When no object is associated with it , it comes to function.
function fun(param1, param2){
// some code...
}
Many answers are saying something along the lines that a method is what a function is called when it is defined on an object.
While this is often true in the way the word is used when people talk about JavaScript or object oriented programming in general (see here), it is worth noting that in ES6 the term method has taken on a very specific meaning (see section 14.3 Method Definitions of the specs).
Method Definitions
A method (in the strict sense) is a function that was defined through the concise method syntax in an object literal or as a class method in a class declaration / expression:
// In object literals:
const obj = {
method() {}
};
// In class declarations:
class MyClass {
method() {}
}
Method Specificities
This answer gives a good overview about the specificities of methods (in the strict sense), namely:
methods get assigned an internal [[HomeObject]] property which allows them to use super.
methods are not created with a prototype property and they don't have an internal [[Construct]] method which means that they cannot be called with new.
the name of a method does not become a binding in the method's scope.
Below are some examples illustrating how methods (in the strict sense) differ from functions defined on objects through function expressions:
Example 1
const obj = {
method() {
super.test; // All good!
},
ordinaryFunction: function ordinaryFunction() {
super.test; // SyntaxError: 'super' keyword unexpected here
}
};
Example 2
const obj = {
method() {},
ordinaryFunction: function ordinaryFunction() {}
};
console.log( obj.ordinaryFunction.hasOwnProperty( 'prototype' ) ); // true
console.log( obj.method.hasOwnProperty( 'prototype' ) ); // false
new obj.ordinaryFunction(); // All good !
new obj.method(); // TypeError: obj.method is not a constructor
Example 3
const obj = {
method() {
console.log( method );
},
ordinaryFunction: function ordinaryFunction() {
console.log( ordinaryFunction );
}
};
obj.ordinaryFunction() // All good!
obj.method() // ReferenceError: method is not defined
A method is a property of an object whose value is a function. Methods are called on objects in the following format: object.method().
//this is an object named developer
const developer = {
name: 'Andrew',
sayHello: function () {
console.log('Hi there!');
},
favoriteLanguage: function (language) {
console.log(`My favorite programming language is ${language}`);
}
};
// favoriteLanguage: and sayHello: and name: all of them are proprieties in the object named developer
now lets say you needed to call favoriteLanguage propriety witch is a function inside the object..
you call it this way
developer.favoriteLanguage('JavaScript');
// My favorite programming language is JavaScript'
so what we name this: developer.favoriteLanguage('JavaScript');
its not a function its not an object? what it is? its a method
Your first line, is creating an object that references a function. You would reference it like this:
myFirstFunc(param);
But you can pass it to another function since it will return the function like so:
function mySecondFunction(func_param){}
mySecondFunction(myFirstFunc);
The second line just creates a function called myFirstFunc which would be referenced like this:
myFirstFunc(param);
And is limited in scope depending on where it is declared, if it is declared outside of any other function it belongs to the global scope. However you can declare a function inside another function. The scope of that function is then limited to the function its declared inside of.
function functionOne(){
function functionTwo(){}; //only accessed via the functionOne scope!
}
Your final examples are creating instances of functions that are then referenced though an object parameter. So this:
function myFirstFunc(param){};
obj.myFirst = myFirstFunc(); //not right!
obj.myFirst = new myFirstFunc(); //right!
obj.myFirst('something here'); //now calling the function
Says that you have an object that references an instance of a function. The key here is that if the function changes the reference you stored in obj.myFirst will not be changed.
While #kevin is basically right there is only functions in JS you can create functions that are much more like methods then functions, take this for example:
function player(){
this.stats = {
health: 0,
mana: 0,
get : function(){
return this;
},
set : function( stats ){
this.health = stats.health;
this.mana = stats.mana;
}
}
You could then call player.stats.get() and it would return to you the value of heath, and mana. So I would consider get and set in this instance to be methods of the player.stats object.
A function executes a list of statements example:
function add() {
var a = 2;
var b = 3;
var c = a + b;
return c;
}
1) A method is a function that is applied to an object example:
var message = "Hello world!";
var x = message.toUpperCase(); // .toUpperCase() is a built in function
2) Creating a method using an object constructor. Once the method belongs to the object you can apply it to that object. example:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
this.name = function() {return this.firstName + " " + this.lastName;};
}
document.getElementById("demo").innerHTML = person.fullName(); // using the
method
Definition of a method: A method is a property of an object that is a function. Methods are defined the way normal functions are defined, except that they have to be assigned as the property of an object.
var myFirstFunc = function(param) {
//Do something
};
and
function myFirstFunc(param) {
//Do something
};
are (almost) identical. The second is (usually) just shorthand. However, as this jsfiddle (http://jsfiddle.net/cu2Sy/) shows, function myFirstFunc will cause the function to be defined as soon as the enclosing scope is entered, whereas myFirstFunc = function will only create it once execution reaches that line.
As for methods, they have a this argument, which is the current object, so:
var obj = {};
obj.func = function( ) {
// here, "this" is obj
this.test = 2;
}
console.log( obj.test ); // undefined
obj.func( );
console.log( obj.test ); // 2
The exact syntax you showed is because you can also do this:
function abc( ) {
this.test = 2;
}
var obj = {};
obj.func = abc;
obj.func( ); // sets obj.test to 2
but you shouldn't without good reason.
ecma document
4.3.31method :
function that is the value of a property
NOTE When a function is called as a method of an object, the object is
passed to the function as its this value.
It is very clear: when you call a function if it implicitly has a this (to point an object) and if you can't call the function without an object, the function deserves to name as method.

How the JavaScript this keyword works?

I have been doing some JavaScript development and I encountered this problem. Consider the following code
var obj = {};
obj.bind = function () {
console.info(this);
};
obj.bind();
I'm running the code on the FireBug JavaScript console. The expected result is that this displays a reference to the object in the console.
It actually displays undefined.
But, when I make this change to my code
var obj = {};
obj.bind = function () {
this.x = 'x';
console.info(this);
};
obj.bind();
Now the console displays the expected value of this, which is a reference to the obj object.
Why does this happen?
undefined is the return value of the function, which you'll get because you're not returning a value explicitly.
In both Chrome and Firebug, it correctly displays the Object in the console before the return value undefined.
So if you do:
var obj = {};
obj.bind = function () {
console.info(this);
return "foo";
};
obj.bind();
...you should see something like:
Object { }
"foo"
If Firebug is not displaying the Object when it is empty, you may need to check to make sure you're using the most current version.
In your example, "this" should be obj, just as some commenters pointed out. Here are the details that explain why --
In Javascript, the value of "this" changes depending on how you call the function:
When a function is stored as a property on an object, and you invoke that function by calling obj.foo(), "this" will be obj.
EX:
var obj = {
x: 1,
increment: function() {
this.x = this.x + 1;
};
obj.increment(); // Makes "this" be obj
When you invoke a function using syntax that does not refer to any owning object, "this" will be the global environment.
EX:
function someFunc(a, b) {
return a + b; // If you were to refer to "this" here, it would be the global env.
}
someFunc(5, 6);
When you invoke a function as if it were a constructor by using the new operator, a new object will be instantiated for you, and "this" will point to that new object.
EX:
function SomeConstructor() {
this.x = 42; // under the hood, a new object was instantiated for you, and "this" was set to it.
}
var result = new SomeConstructor(); // note the "new" keyword
// result will be { x:42 }
When you use call() or apply(), you can control what "this" is.
(No example here since it's fairly far from your question. Look up docs for apply() or call() for an example.)

Very basic Javascript constructors problem

In the following JavaScript code main() is called.
My question is why the second constructor is called rather than the first one ?
What am I missing here ?
Thanks !!
function AllInputs() {
alert("cons 1");
this.radioInputs = [];
alert(this);
}
function AllInputs(radioElement) {
alert("cons 2");
this.radioInputs = [radioElement];
alert(this);
}
AllInputs.prototype.toString = function() {
return "[object AllInputs: radioInputs: " + this.radioInputs.length + "]";
}
function main() {
var result = new AllInputs();
}
Javascript does not support overloaded functions.
When you define the same function twice, the second definition replaces the first one.
Instead, you should make a single function, and check arguments.length to see how many arguments were passed.
For example:
function AllInputs(radioElement) {
this.radioInputs = arguments.length ? [radioElement] : [];
alert(this);
}
In JavaScript, the last definition of an identifier is used:
function foo() { return "bar"; }
var foo = "foo";
alert(foo);
In that case, foo was a variable with the value "foo". Had foo been a function, it would have simply said that foo was a function. If you don't believe it, try using alert(foo()) instead of just alert(foo). You'll most likely get an error in your console log with no visible output like you had with alert(foo) (the variable...not the function call).
function foo() { ... }
is really just shorthand for
var foo = function () { ... }
Hence, the second time you're declaring the function, you're overwriting the variable AllInputs with a different function. There ain't no such thing as two functions with the same name in Javascript, since all functions are really variables.

Categories