I'm trying to use variables placed inside a function. I'm not looking to do anything particular with this piece of code, but I want to figure out why bind / apply / call work for objects, and not functions.
function another () {
this.var = 'another test'
}
function test (){
this.var = 'test123'
console.log('this.first: ',this.var);
}
var bind = test.bind(another);
console.log('bind: ', bind());
.bind() works just fine for functions. It just doesn't do what you think it does.
See, functions are objects too. And treating them like objects doesn't mean they get called.
function a() { console.log("a was called"); }
function b() { console.log(this); }
var bound = b.bind(a);
bound(); // logs "function a() { }" in my console
In your case, once you've bound test to another, you have a new function that works just like test, but where this means another, and thus this.var means another.var. And all of this happens without another ever getting called.
I'm not sure entirely how you expect your code to work, cause it doesn't make much sense as it stands. But if you were to examine things after you run it, you would find that another.var now has the value 'test123'.
Even if you said another() beforehand, it wouldn't matter. Firstly because another isn't bound to anything, so to it, this means the global object. In a browser, another() would basically just be setting window.var. But secondly, test sets its own value -- so even if both functions had the same idea of what this.var means, test would overwrite it with 'test123'.
This will log "another test", since this defaults to window:
function another() {
this.foo = 'another test';
}
another();
console.log(window.foo);
edit:
// define function object window.first:
function first() {
this.foo = 'first';
}
// define function object window.second:
function second() {
this.foo = 'second';
}
// call window.first, sets window.foo to 'first':
first();
// set window.bound to a new function object which
// runs second in the context of the object first:
var bound = second.bind(first);
// call window.bound, which sets window.first.foo to 'second':
bound();
// call second, which sets window.foo to 'second' then logs the return
// value of second, which is undefined:
console.log('second: ', second());
Related
Hi Beginner here so sorry for any ignorance if I showed.
const test = {
myfunction(){
console.log(this);
},
myfunction3(){
function myfunction4(){
console.log(this)
}
return myfunction4()
} }
and when I run
test.myfunction3()
I receive global object as a window. I am a little bit confused how this happened. My question is
myfunction3() can access to myfunction4() because of its hierarchy? If so, is there anyway I can access to myfunction4() directly instead of going through myfunction3()?
Why this in myfunction4() returned global window instead of a reference to myfunction4()?
Thank you for your help!
1. You cannot access myfunction4 in such method of "test.myfunction3.myfunction4()"
Because myfunction4 is not property of myfunction3 and especially, test.myfunction3 is not object.
2. Since myfunction4 is not method, instead it is function, "this" refer Window object in myfunction4.
"this" in method refer the parent object but in function, it refer global object like Window.
The reason you're getting the global object has to do with your function call/invocation and not with the function placement itself.
Invocation, I'm referring to ==> test.myFunction3()
Object methods often times are a bit confusing, but just because a function sits inside of another function means nothing. It's not about placement of a function but its invocation.. so here what matters is test.myFunction3()
myfunction3() can access to myfunction4() because of its hierarchy? If so, is there anyway I can access to myfunction4() directly instead of going through myfunction3()?
You can't access the function directly through myFunction3(), but you can return a reference to it, which you can then use. See below where I point out that you have a typo in your implementation of myFunction3()
const func4 = myFunction3();
func4();
Why this in myfunction4() returned global window instead of a reference to myfunction4()?
There are two issues, first this in a function is bound at runtime.
Second, because of typo in myFunction3() you are returning the result of calling myFunction4 rather than returning a reference to the function itself, which I assume is what you are trying to do.
myfunction3(){
function myfunction4(){
console.log(this)
}
return myfunction4; // this returns the function, rather than return the result of calling the function (drop the () )
}
Perhaps you just needed to convert it into an object for the function call to work like this:
var name = 'global'; // when 'this' scope is global
var test = {
name: 'local', // when 'this' scope is local to test
fun1: function() { //same fun as an object
console.log(this.name);
},
fun3: function() {
function myfunction4(){
console.log(this.name);
}
return myfunction4()
}
}
And if you wanted to call the functions in the same way you were doing it above, then you could it have done so like this:
test.fun1(); // local
test.fun3(); // global (that's what inside of fun4)
You cannot call fun4 directly but can findout the value by calling fun3.
I am just getting more into javascript and wandering what is the difference between
var myfunc = function(){
publicfunctions = {}
publicfunctions.function1 = function(){do smthing and return}
return publicfunctions
}
and
var myfunc = function(){
this.function1 = function(){do smthing and return}
}
It seems to me that both doing the same thing
Also can someone explain what is difference between
var func = (function myfunc(){ .. do smthing and return .. })();
and
var func = function myfunc(){ .. do smthing and return .. }
var newfunc = new myfunc()
Thanks
Let's go step by step.
example:
a) you define a function that returns an object (careful with variable declaration - you should declare it with var keyword in order to scope it to your function. That objects has a single property that points to a function. Never the less, your first function is assigned to a variable myfunc
Now, if you try to call myfunc(), you'll get an object with single property function1. Nothing special here.
b) you define a function again and assign it to myfunc variable, only this time it contains this keyword which assumes you're trying to utilize this function as a constructor. In this example, merely calling myfunc produce no output since you haven't returned anything from a function. However, calling a function with preceding keyword new will result in object creation.
var myObj = new myfunc();
// `this` keyword now refers to myObj which means myObj can call `function1`
example:
a) On the righthand side is something that is called IIFE (or Immediately Invoked Function Expression). Basically means, a function expression that is created and executed, well, immediately. So func should receive whatever that function returns.
b) Yet again, facing a constructor, only this time you actually assumed myfunc is a constructor when you added new keyword before myfunc execution. Creates an object to whic newfunc now points to and has authority over.
Note:
In constructor functions (the ones that you call with new keyword), this is implicitly returned and no need for explicit return. Now, if you want to test it and return something else instead, I'll leave it up to you to explore and see what you'll end up with. :)
Since it's a broader topic in itself, I recommend this excellent book by Nicholas Zakas. It really answers a lot of JS questions.
I am stumbling upon a problem that I have seen before, but that I couldn't solve before. I will likely stumble upon it again in the future, so please, someone explain it to me what is going on?
In the partial snippet of javascript below, I have a function that populates a screen, including an order combobox (twitter bootstrap). When I click on one of the order items in that combobox, it should invoke the function clsModCampaigns.blnCompaniesListReload().
For a reason that I don't understand, once inside the '$.each' iterator, the global object reference 'objModCampaigns' is lost? I get a successful alert '1', but not an alert '2'.
Within the $.each, I would like to use 'objModCampaigns.arrOrderBy' instead of 'this.arrOrderBy', but the $.each iterator only seems to work this way. Why is it working this way??
What is going on with 'this', or with variables/objects assigned in the root of the class with 'this'?
Is $.each just special??
function clsModCampaigns(objSetSystem, objSetModuleBase)
{
objModCampaigns = this;
arrOrderBy = {
intID: 'ID',
strName: 'Name'};
[...]
this.blnScreenCampaignInitialize = function (fncSuccess,fncError, intID) {
$.each(this.arrOrderBy, function (strFieldName, strFieldDescription) {
if(strFieldName != 'datDeleted' || objSystem.blnHasPerm("CAMPAIGNS_DELETED")) {
strOrderByID = "ulCampaignsCompaniesListOrderBy" + strFieldName;
$("#ulCampaignsCompaniesListOrderBy").append('<li>'+strFieldDescription+'</li>');
$("#"+strOrderByID).unbind("click").bind("click", function() {
alert("1");
objModCampaigns.arrCurrentShownCompanies.strOrderBy = strFieldName;
objModCampaigns.blnCompaniesListReload();
alert("2");
});
}
});
return true;
};
}
The code you have is
$.each(this.arrOrderBy, ...);
You want
$.each(arrOrderBy, ...);
The reason for it is the this context on that line is different because it is inside a new function this.blnScreenCampaignInitialize.
This is just a part of how JavaScript works
var message = "hello";
function welcome() {
console.log(message);
}
welcome(); // "hello"
P.S. use var
If you don't use var, you'll be attaching all of your vars to the global object.
function hello() {
foo = "bar";
console.log(foo);
};
hello(); // "bar"
console.log(foo); // "bar"
// Holy smokes! `foo` has escaped our `hello` function!
Compare that to
function hello() {
var foo = "bar";
console.log(foo);
}
hello(); // "bar"
console.log(foo); // ReferenceError: foo is not defined
// much better
Now let's see a terrible example
function a() {
b = 5;
return b;
}
function b() {
return "function";
}
console.log(a()); // 5
console.log(b()); // TypeError: number is not a function
This is happening because we didn't use var properly. We first define b as a function but after running a(), b is now set to 5. The second log statement is the equivalent of trying to run 5() because b is no longer a function.
P.P.S. it's pretty unconventional to prefix your vars with str, int, fnc, obj, or cls in JavaScript.
I understand you're a "VB guy" according to your comments, but that's no excuse for bringing your own conventions to the language. I see in your profile that you're fluent in Dutch, English, German, and French. I would recommend you treat learning programming languages much the same as spoken languages: each of them have their own explicit set of rules and conventions.
Here's a heap of free JavaScript books for you. I hope they can help you learn some more basics.
P.P.P.S. Overall, your function is really big as it is, and I can see you already truncated some of the code with your [...]. The whole thing could probably benefit from some better composition.
If you paste all of your code, maybe someone could help you better.
What is going on inside the $.each() ?
Regarding you question title, I'm trying to answer:
// each function in source
function (obj, callback, args) {
//...
}
Check the source of complete $.each function by yourself, you can see any function's source code just by typing the function name in the appropriate text box (the second on top).
Here in each function, the array/object passed in to the each function (the first argument) is being run through a loop and each value is being passed in to the callback (second argument) and that call back is getting executed like:
callback.apply(obj[i], args);
So, the passed callback in the each function is being executed each time the loop occurs ad the current value in the loop is passed as the argument of callback function along with the third argument args.
If your function function clsModCampaigns(){ //... } is a normal function then this inside this function points to global window object. so just use:
$.each(arrOrderBy, ...);
instead of
$.each(this.arrOrderBy, ...);
Because, arrOrderBy is within the direct scope so arrOrderBy is accessible directrly. For example:
function someThing()
{
var x = 'y'; //<-- this scope (everything inside someThing) is
// global for somethingElse inner function
function someThingElse)(x) //<-- possible to use directly
{
}
}
The keyword this behaves differently depending on the context. Check about this on MDN.
I have an object and it has another inner object. How can I call the parent object from the inner object?
var test = {
init: function () {
var instance = this;
},
call: function() {
this.stop(); // works
},
stop: function() {
this.parseText(); // works
},
parseText: {
load: function ()
{
this.call(); //*** dont work
instance.call(); // work, but what if i have this instance (same name) on another object, would'nt this conflict it?
}
}
};
I'm using an instance, which works fine, but what if I or someone wrote an instance (same name) var in another object, wouldn't it will conflict and overwrite this instance?
Eric's answer gives you a reasonable example of how to do what you want to do, but doesn't really go into why.
In JavaScript, this is set entirely by how a function is called (for now; see below the fold for details), not where the function is defined as it is in some other languages that have the same keyword (Java, C++, C#, ...).
You, the coder, determine what this will be each time you call a function. There are two main ways: By calling the function via an object property (in the same expression), or explicitly using the function's built-in call and apply functions.
Via an object property
Using an object property:
obj.foo(); // or
obj["foo"](); // both work
That does two very distinct things, but which collaborate to set the this value: First, the function reference is found by looking up the foo property of the object obj. Then, the function is called. Because you called it as part of the same overall expression retrieving the property value, the JavaScript engine will set this to obj within the call.
So in your example, test.parseText.load(), within the load call this will be parseText, not test, because that's the object on which load was looked up.
Note that setting-this-via-property-lookup only works when they're done at the same time. This does not work:
var f = obj.foo;
f(); // `this` will not be `obj` within the call
That doesn't work because they weren't done at the same time. The property lookup and function call were separated.
Using call or apply
The second way of setting this is more explicit: All functions have the call and apply properties, which are themselves function references that call the function using information you supply. In both cases, the first argument is the object to use as this during the call. So if we wanted to fix the example above that didn't work, we could do this:
var f = obj.foo;
f.call(obj); // `this` will be `obj` within the call
f.apply(obj); // same
The only difference between call and apply is how you supply function arguments. With call, you supply them as further discrete arguments to the function; with apply, you pass in an array of arguments.
So these all do the same thing:
// 1 - Directly via property
obj.foo("a", "b", "c");
// 2 - Using `call`
f = obj.foo;
f.call(obj, "a", "b", "c");
// 3 - Using `apply`
f = obj.foo;
f.apply(obj, ["a", "b", "c"]); // Note the `[ ... ]`, one array with three elements
You can see how call and apply could work with your existing structure:
test.parseText.load.call(test.parseText);
That calls test.parseText.load, making this = test.parseText within the call.
What Eric did in his answer was to use a closure to make it simpler for you to call parseText with the this value you expect.
Further reading (disclosure: from my blog):
Mythical methods
You must remember this
Closures are not complicated
Up top I said:
In JavaScript, this is set entirely by how a function is called
(for now...
The reason I said "for now" is that in ES6, JavaScript is getting "arrow functions" and unlike other functions, the value of this within an arrow function is set by where they're created, not how they're called: They get this from the context where you create them.
Suppose you were writing code in an object method and wanted to use another method of the object to, I don't know, output information from an array (yes, this is contrived). In ES5, you'd probably do this:
this.output("Entries:");
theArray.forEach(function(entry, index) {
this.output(index + ": " + entry);
}, this);
// ^------- tells `forEach` what to use as `this` during the callback
If you left off the argument, you'd have a bug:
this.output("Entries:");
theArray.forEach(function(entry, index) {
this.output(index + ": " + entry); // <== Bug, `this` is either
// `undefined` (strict) or
// the global object (loose)
});
But since arrow functions inherit this from where they're created rather than getting it based on how they're called, the arrow function version of that doesn't need the second argument:
this.output("Entries:");
theArray.forEach((entry, index) => {
this.output(index + ": " + entry);
});
If all you're worried about is test changing, do it like this:
var test = (function() {
var object = {}
object.call = function() {
this.stop(); // works
};
object.stop = function() {
this.parseText(); // apparently works, even though parseText is not a function
};
object.parseText = {
load: function() {
object.call(); // works
}
};
return object;
})();
If you don't know the name of test, you can use a self-invoking anonymous function to create a wrapper, and refer to the object as shown below.
Note that test is not a reference to a function, but to the return value of the anonymous function. Because the object name (obj) is wrapped inside a function, it cannot be read or modified from outside
The solution below is neat, does not pollute the scope of test, and works like a charm. As mentioned earlier, test refers to the same object as obj. It's however not possible to manipulate variable obj, from outside, so that the code inside the function breaks.
var test = (function(){ //Self-executing function
var obj = {
call: function() {
this.stop(); // works
},
stop: function() {
this.parseText(); // works
},
parseText: {
load: function ()
{
obj.call(); // obj refers to the main object
}
}
};
return obj; //Return the object, which is assigned to `test`.
})(); //Invoke function
Update
It's not possible to reliably refer to self, this, or any reference to the object inside an object, without wrapping it.
Your current solution does not work, see comments in the code below:
var obj = {
init: function(){
var instance = this; //`instance` is declared using `var` inside a function
}, // This variable cannot read from "the outside"
parseText: {
load: function(){
instance.call(); //Does NOT work! instance is not defined
}
}
}
"call" is actually a built-in function on the function object that can be used to call the function specifying what to use for this. How does your code work? It doesn't seem like it should since parseText isn't a function...
Maybe try this:
parseText: function() {
var load = function ()
{
this.call(); //*** should work
};
load.call(this);
}
I have a function like this:
function run(arg) {
if (!window.alreadyRun) init();
window.alreadyRun = true;
/* more code */
}
You get the idea, I'm trying to figure out if it's the first time a function is called.
Is there a better way to do this? Without using globals? Something like this:
function run(arg) {
var ranAlready;
if (!ranAlready) init();
ranAlready = true;
/* more code */
}
This will return a function, with a variable called runCount which will hold the number of times it was called.
var yourFunction = function() {
var runCount = 0;
return function() {
console.log(runCount);
runCount++;
}
}
var a = yourFunction();
a(); // runCount: 0
a(); // runCount: 1
a(); // runCount: 2
a(); // runCount: 3
See it on jsFiddle.
If you just want to run an init type function, you could place the code above returning the inner function. It will be called once before returning the inner function, and its scope will retain to its outer function.
The power of closures.
var f = (function(run) {
return function() {
if (!run) init(),run=true;
// do code
};
}(false));
You can even use if (!run) init() && run = true and get init to return false if you want it to be called again on the next function call.
We have a self executing function which creates a local run variable and set's it to false by passing it in as an argument. We then have a single line which checks if it's false if so it does init(), run=true which is running the init function and assigning it to true in a single expression.
Basically anywhere were your using global scope to make the variable static to the function you can instead use a closure as a scope level between local function scope & global scope.
If you need a variable that is static to a function & read only you can use the little known const keyword.
I think closures are completely overkill for this, and only complicates the code.
What you're describing is known as a static variable in Object Oriented languages, and it can be mimicked quite easily in JS by attaching properties directly to the function. This is possible because functions are first-class objects in JS:
function run(arg) {
if (!run.ranAlready) { // run.ranAlready is undefined at first, so falsy
run.ranAlready = true;
init();
}
/* more code */
}
This is far simpler than nested functions, and you can continue to use run() in exactly the same way.
Another advantage is that, for unit testing, you can still access the ranAlready property from outside the function to check that your code is working correctly:
assert(run.runAlready == false);
run();
assert(run.runAlready === true);
Granted, this can't be used for anonymous functions, such as in event handlers, but isn't it much cleaner to give that anonymous function a name instead of using nested functions and an extra function invocation?
Here's just another way to do it. You can have the function modify itself. In the case below, myfunction gets changed to a new one. This may not be exactly what you're looking for but I think it's useful to at least post this so you can see alternative ways to do things (and also: self modifying code can just be cool at times).
var myfunction = function() {
alert("This is the first time I'm executed");
myfunction = function() {
alert('Subsequent times');
}
}
myfunction(); // displays the alert 'This is the first time...'
myfunction(); // displays the alert 'Subsequent times'
myfunction();
Example: http://jsfiddle.net/jonathon/wntmB/