Let's say I have these two functions:
function fnChanger(fn) {
fn = function() { sys.print('Changed!'); }
}
function foo() {
sys.print('Unchanged');
}
Now, if I call foo(), I see Unchanged, as expected. However, if I call fnChanger first, I still see Unchanged:
fnChanger(foo);
foo(); //Unchanged
Now, I assume this is because foo is not being passed to fnChanger by reference, but I may be wrong.
Why does fnChanger not change foo to print Changed!?
Furthermore, how can I get fnChanger to change foo without too much messy syntax?
PS: I'm using node.js to test all this stuff, so that's where the sys.print comes from.
The assignment to the fn argument just makes that identifier to point to the anonymous function, foo in the outer scope is not affected.
When you pass an object as an argument, one can say "references are passed by value". The assignment just replaces the location where the fn identifier refers to.
That's how the evaluation strategy works in JavaScript.
Just before the assignment in the fnChanger functions, the two identifiers, the global foo and the fn argument, point to the same function object:
---------------------------------------------
foo -----> |function foo { sys.print('Un changed!'); } |
---------------------------------------------
^
|
fn -------------
After the assignment, fn will simply point to the new function:
---------------------------------------------
foo -----> | function foo { sys.print('Unchanged!'); } |
---------------------------------------------
---------------------------------------
fn ------> | function { sys.print('Changed!'); } |
---------------------------------------
How could you change it?
Well, assuming that foo is a function in the global scope, you could do something like this:
function fnChanger(obj, name) {
obj[name] = function() { sys.print('Changed!'); };
}
function foo() {
sys.print('Unchanged');
}
fnChanger(this, 'foo');
foo(); // Changed!
The above will work because in the fnChanger function, we require a base object and a property name, functions declared in the global execution context are bound as properties of the Global object, therefore we can re-assign its value in that way.
The line fnChanger(this, 'foo'); should be executed also in the Global scope, it will pass the this value (which refers to the Global object in this scope) and a property name, allowing you to make an assignment to the GlobalObject.foo identifier.
If that code were inside a function, there is no way we can get a base object, because in this "Function Code Execution Context", function declarations (variable declarations and function formal parameters also) are bound as properties of a non-accessible object, called the Variable Object (a chain of these Variable Objects, forms the Scope Chain), and if it were the case, the only workaround would be to use eval.
More info:
ECMA-262-3 in detail. Chapter 8. Evaluation strategy.
As #CMS pointed out you cannot assign it within the function due to the scope. However you could reassign it like this:
var fnChanger = function() {
return function() {
alert('changed!');
}
}
var foo = function() {
alert('Unchanged');
}
foo = fnChanger();
foo();
example
There is an elegant way around it
function fnChanger(fn_holder) {
fn_holder["fn"] = function() { console.log('Changed!'); }
}
function foo() {
console.log('Unchanged');
}
const foo_holder = {fn: foo}
fnChanger(foo_holder);
foo_holder["fn"](); // Changed!
Short explanation:
Pass a higher level reference foo_holder to fnChange like a hash (or an array).
Reassign your element in side the hash foo_holder["fn"] to a new value. This will change where the inner reference is pointing instead of creating a new reference.
Then you're good to have fun with your updated function.
In Javascript, functions are first class objects that can be treated just as another variable. But for the function to return its result, it has to be first invoked.
When you are invoking the fnChanger(foo), the fn variable actually gets overridden with foo().
But you are not getting the result because that function was never invoked. Try returning it and invoking as given below and you will the required answer.
function fnChanger(fn) {
fn = function() {
console.log('Changed!');
}
return fn;
}
function foo() {
console.log('Unchanged');
}
fnChanger(foo)();
foo();
Related
I can invoke function inside the object, but I can't invoke function inside the function.
How it really works?
const baz = {
bar() { console.log('hi');}
}
baz.bar(); // -> hi
function foo() {
function bar() {
console.log('there');
}
}
console.log(foo.bar); // undefined, why???
Because in your second example, foo has no bar property on it, but foo.bar looks for a property called bar on the foo object. If your question comes from the fact both of your examples use {}, then: in JavaScript {} are used for a least a couple of different things:
Delimiting an object literal, as in your first example
Delimiting the body of a function, as in your second example, or a block (for instance, the block attached to an if or for or similar)
Those are completely unrelated things, they just look somewhat similar. (There are other things {} are used for, such as indicating named imports [import { x } from "y"], object destructuring [though really that's just the converse of #1 above], probably others...)
Also note that with your code, a bar function is only created if and when you call foo, and a different bar function is created every time you call foo.
You can assign a function to a property on another function, though, just not that way. For instance:
function foo() {
console.log("foo");
}
foo.bar = function() {
console.log("bar");
};
foo.bar(); // "bar"
foo(); // "foo"
That works because, as you said, functions are objects, so you can add properties to them.
If you want a more similar declarative syntax, you can create an object with the functions and copy them to the target function via Object.assign:
// Object.assign copies properties from the second argument onward
// onto the object in the first argument
const foo = Object.assign(
// Function expression, creates a function:
function foo() {
console.log("foo");
},
// Object literal, creates an object:
{
bar() {
console.log("bar");
}
}
);
foo.bar(); // "bar"
foo(); // "foo"
var fn;
function foo() {
var a = 2;
function baz() {
console.log( a );
}
fn = baz; // assign baz to global variable
}
function bar() {
fn(); // look ma, I saw closure!
}
foo();
bar(); // 2
I have no idea with this code:
First, why the author have to wrap fn in a function that call fn(function bar), why don't call is simply outside the global scope like "fn();",I've tried it and result in the same
Second, is it a good way to assign a function to a variable?, I thought it could only copy the structure of the function and reconstruct in the variable(which means it have no reference or simply cannot remember the environment by foo)
Third, The author said that engine remain all the closure whenever there is one who using what concern to that environment, but here, I just see that there's a assignment, so is it right if fn is using baz that leads to the remain of environment of foo to fn?(which make fn can use the variable "a")
Maybe the title sounds a little bit weird (please improve it) -- but I need a solution for the following scenario. I have the following code:
var Foo = function () {
this._hello = "world!";
};
Foo.prototype.bar = function () {
console.log(this._hello);
};
var f = new Foo();
f.bar(); // => "world!"
f.bar.apply(this); // => undefined
I know that apply changes the context, so inside of bar, this will be the global object (at the second call).
But what I need is to access this from Foo function. A solution that I see would be:
var Foo = function () {
var self = this;
self._hello = "world!";
self.bar = function () {
console.log(self._hello);
};
};
However, I would choose not to have method declarations inside of another function.
I'd prefer to define methods same column level (just for code style):
var Foo = ...;
Foo.prototype.method = ...;
Is this possible? How?
You can use the bind() method to tackle these kinds of problems. Instead of something.method(f.bar) call something.method(f.bar.bind(f)) to get the bar method always called on the expected context (f).
If you don't want to use bind in every location where you pass bar around as a callback, you can also put it in the constructor to create a dedicated bound function for every instance by default:
function Foo() {
this._hello = "world!";
this.bar = this.bar.bind(this);
}
Foo.prototype.bar = function () {
console.log(this._hello);
};
var f = new Foo;
something.method(f.bar); // works!
It's not possible to do this by assigning a function to the prototype like this.
Unless you assign something to f.bar directly (as in your second example, and Bergi's answer), the value you will get for f.bar is a reference to the function you assigned to the prototype's property Foo.prototype.bar. This will be exactly the same function object for any other object that has Foo.prototype as a prototype. There is no reference to f in this function object.
So when you call f.bar(), how does this refer to the value of f? It is a special syntax, that basically equates to f.bar.apply(f). It is only the fact that you use this method-call syntax that sets this to the value of f. Any other reference to f.bar will just evaluate to the prototype's single, shared function object.
If you call it with f.bar.apply(somethingElse), this is now set to somethingElse, and all association with f is lost.
It's not a question of apply(...) changing scope. fn.apply(x) sets this to x within fn, whereas y.fn() sets this to y.
Similarly, in your example if you assign f.bar to a variable and then invoke it via the variable instead of using the method-call syntax f.bar(), your this will be the window object (if running in a browser) and again you'll get undefined.
var func=f.bar; // now func === Foo.prototype.bar
func(); // => undefined
See also How to find the object a function belongs to?
Suppose I have functions like:
function foo() {
}
function bar() {
}
I can write above as Object Literal notation:
var Baz = {
foo: function() {
},
bar: function() {
}
};
As far as I understand in the later case, an instance of Baz will be created when the script loads regardless if any Baz function is ever called. In the former case, function object is only created when that function is called. Am I correct about these assumptions?
If I am correct then the former would have higher performance (less memory) than the later in application where these functions are rarely called.
But the advantage of the later is that it gives greater modularity and lower global namespace pollution.
What is your take on this from your professional experience?
Is there a speed difference?
In the former case, function object is only created when that function is called.
No, the functions are created regardless.
Note that you can also do this:
function foo() {
}
function bar() {
}
var Baz = {
foo: foo,
bar: bar
};
Or this:
var Baz = (function() {
function foo() {
}
function bar() {
}
return {
foo: foo,
bar: bar
};
})();
The primary purpose of putting the functions on Baz as properties is to make them available as "methods" on Baz. This might be for convenience, for "namespacing", etc. In your first form (and my first form above), if that code is at global scope, foo and bar are added to the global scope, which can get pretty crowded pretty fast (esp. on browsers). In your second example, the only global symbol is Baz because the functions are anonymous. In my final example above, the only global symbol is Baz but the functions aren't anonymous, they have names that debuggers and stack traces can show you (which is a good thing; more here).
In terms of trying to optimize when functions get created, here's how it works: When execution enters a given context (the global context, or the context related to calling a function), these things are done:
A behind-the-scenes execution context object is created.
A behind-the-scenes variable object for that execution context is created.
In the case of a function context:
A property is added to the variable object for arguments (the array-like thing you can use to access arguments)
A property is added to the variable object for each of the function's named arguments, with the value of the argument
If the function has a name, its name is added as a property of the variable object and has the value of the function object.
Properties are created on the variable object for each variable declared with var in the execution context; their values are initially undefined (regardless of whether the var has an initializer on it).
Every function declaration in the context is processed. (Function expressions are not processed yet; more on the difference below.) A property on the variable object for each function name is created and receives the function object as its value.
Step-by-step code execution begins.
Like all expressions, function expressions are evaluated when they're encountered in the step-by-step flow.
var statements that have initializers (e.g., var a = 2;) are treated exactly like assignment statements (a = 2;); the var aspect of it was done much earlier. (var is frequently misunderstood. For instance, we had this question just yesterday.)
You'll note the difference above between function declarations and function expressions. You can tell which is which by looking to see whether you're using the result as a right hand value — that is, are you assigning the result to a variable, using it as the right-hand side of a property definition in an object literal, or passing it into a function. If you are, it's a function expression. If you're not, it's a function declaration.
Function declaration example:
function foo() {
}
Function expression example:
var foo = function() {
};
Another:
var Baz = {
foo: function() { }
};
(The foo line is a property declaration in an object literal that uses a function expression for the value.)
Named function expression example:
var f = function foo() { // <== Don't do this (more below)
};
Named function expressions should be valid, but they're poorly-supported by implementations in the wild (particularly IE) and so for now they must be avoided. More here.
My question is:
function Foo()
{
this.foo = "bar"; // <- What is "this" here?
}
From what I can tell it depends on how Foo is used, i.e. as a constructor or as a function. What can this be in different circumstances?
The this keyword refers to the object the function belongs to, or the window object if the function belongs to no object.
It's used in OOP code, to refer to the class/object the function belongs to
For example:
function foo() {
this.value = 'Hello, world';
this.bar = function() {
alert(this.value);
}
}
var inst = new foo();
inst.bar();
This alerts: Hello, world
You can manipulate which object this refers to by using the apply() or call() functions. (A very very handy feature at times)
var bar1 = new function() {
this.value = '#1';
}
var bar2 = new function() {
this.value = '#2';
}
function foo() {
alert(this.value);
}
foo.call(bar1); // Output: #1
foo.apply(bar2, []); // Output: #2
Read what Douglas Crockford has to say on the matter, to quote him from A Survey of the JavaScript Programming Language:
A function is an object. It can contain members just as other objects. This allows a function to contain its own data tables. It also allows an object to act as a class, containing a constructor and a set of related methods.
A function can be a member of an object. When a function is a member of an object, it is called a method. There is a special variable, called this that is set to the object when a method of the object is called.
For example, in the expression foo.bar(), the this variable is set to the object foo as a sort of extra argument for the function bar. The function bar can then refer to this to access the object of interest.
In a deeper expression like do.re.mi.fa(), the this variable is set to the object do.re.mi, not to the object do. In a simple function call, this is set to the Global Object (aka window), which is not very useful. The correct behavior should have been to preserve the current value of this, particularly when calling inner functions.
Also 'this' can change depending on how your function is invoked, read on apply function and call function.
I would recommend that you spend time learning form one of JavaScript's greatest minds in his (free) presentations, linked from here.
In JavaScript, the convention (and this is only a convention) is that any function that begins with a capital letter is to be used as a constructor. Then, one would call
var foo = new Foo() and this would refer to the newly created object that is about to be referenced by foo.
Of course, there is nothing stopping you from calling Foo() on its own, in which case this would then refer to the object from which the function was called. To avoid confusion, that is not recommended.
Its depends on how that function is used, there are two basic types in which we can use functions
Function
Function as an Object, by using new keyword
will see one by one
1.Function
var example = function () {
console.log(this);
};
example();
Output : window
Here 'this' keyword points to window object.
By default, this should always be the window Object, which refers to the root - the global scope. So when we console.log(this); from our function, as it’s invoked by the window (simply just called), we should expect the this value to be our window Object:
2.Function as an Object
var example = function () {
console.log(this);
};
var obj = new example();
Output : example {}
Here 'this' keyword points to newly created example object.
In NodeJS there is some interesting behaviour:
function foo() {
this.name = 'bar' // <- What is "this" here?
}
foo() // <- TypeError: Cannot set property 'name' of undefined
But using an arrow function:
const bar = () => {
this.name = 'foo'
console.log(this)
}
bar() // <- { name: 'foo' }
I was always under the impression that a traditional function literal had its own context but not arrow functions, this seems to contradict my understanding.
Given this behaviour the code by the OP would not work...
In JavaScript everything is object even functions. When you say this.foo in following code
function Foo()
{
this.foo = "bar"; // <- What is "this" here?
}
foo becomes member variable of Foo object