Purpose of var a = b.c = function(){} syntax - javascript

I've lately browsed js code and the following syntax keeps coming up:
var foo = bar.bi = function() {...}
This is unfamiliar syntax to me. Is it only to define two names for the same function? If so, why not only define it as bar.bi = function()?

Assigns the same value to the variable and the bi property of the bar object at the same time.
This way the object's property gets the value, but you can still reference it as a variable, which is likely a little faster.
Effectively the same as...
bar.bi = function() {...};
var foo = bar.bi;
foo === bar.bi; // true
Or you can visualize it as...
var foo = ( bar.bi = function() {...} );
So the assignment to bar.bi happens first. The result returned from the assignment expression is the same function, and that result is assigned to foo.

In addition to assigning the function to 2 variable, the context also changes depending on how you call it.
bar.bi();
would have it's context as the bar object, as if you would have used this:
foo.call(bar);
But using it off the other variable, like this:
foo();
would use the context of foo. So if foo is in the global context, it'll be equivalent to this:
bar.bi.call(window);

It's just a compound assignment
var r = x = 3;
assigns 3 to x, and also to r, which is newly declared.
Your example just substitutes a function in place of 3, and an object property—bar.bi—in place of x.

It depends on where it is used.
Both fooand bar.bi point to same function here. That means the function can be invoked using
foo();
and
bar.bi();
At the same time it differs in the value of this inside the function. To make the first one equal to second one, it should be invoked as given below
foo.call(bar);
or
foo.apply(bar);
This ensures that this will point to bar inside the function.
please refer:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply.
.

var foo = bar.bi = function() {...};
bar.bi === function() {...} //true
foo === bar.bi //true
bar will be an object who responds to method bi.

Related

Why does `this` create a global variable instead of using the variable from the call site?

I'm reading the You Don't Know JS books and am on this and Object Prototypes.
I get that to know what this refers to I need to look at the call-site. And the call site is what this will refer to. What I don't get is why this code isn't working as I think it should (I only wrote it to understand this, not for any working problem or anything).
function foo() {
console.log(foo.hasOwnProperty('a')); // 1
console.log(window.hasOwnProperty('a')); // 2
console.log(this.a); // 3
this.a++;
console.log(window.hasOwnProperty('a')); // 4
}
function bar(){
foo.a = 42;
foo();
}
bar();
If you look at the first line in bar which creates an a property for foo and assigns it the value 42. If I comment this line out, then running console.log(foo.hasOwnProperty('a')); gives me false. And if I have it run, then it returns true. But if this is the case, then calling bar is indeed creating an a property for foo, right? This leads to question 3.
I get that at this point window.a does not exist.
Why does this return undefined? this should resolve to foo.a, right? Because the context of this would be in bar, correct? Bar is the call-site. However, this remains undefined regardless of whether foo.a = 42 is commented out or not.
Why does this return true now, after running this.a++? How and why is a global variable being created?
Note: this is just an easy way of thinking about this. In complicated cases (such as when using .bind() or OOP), the following might not be accurate.
this, by default sorta refers to the object that contains the function being called. For example, if I did
var obj = {
fxn: function() {
console.log(this.bar);
},
bar: 3
}
obj.fxn(); // (1)
var fxn = obj.fxn();
fxn(); // (2)
(1) Will print "3" to the console; Because you are, in a way, calling fxn "through" obj, this will point to obj. In other words, because you are calling the copy of fxn that is stored inside of obj, this will point to obj.
(2) Will (assuming bar has not been defined elsewhere) print undefined. That is because fxn isn't being called "through" anything. As a result, it pretends that fxn is being called through window.
Although in your example, foo is being called in bar, bar does not call a version of foo being... well, stored inside itself. bar does not call foo... "through" foo.
Admittedly, that's pretty confusing. Maybe this will clear up some confusion: If you change bar to this:
function bar(){
foo.a = 42;
foo.foo = foo;
foo.foo();
}
it will print 42 instead of undefined. The important part is that the object that foo is being called through will be this. For instance,
function bar(){
var baz = {};
baz.a = 42;
baz.foo = foo;
baz.foo();
}
Will also print 42.
In foo this refers to the parent object - i.e. window.
so this.a and window.a are referring to the same thing.
Because the context of this would be in bar, correct?
Incorrect. For bar to be "this" in foo you would need to apply or call or bind foo passing your desired "this" as context. i.e.
foo.call({});
or
foo.bind({});
Would make "this" and empty object within foo.
Why does this return true now, after running this.a++? How and why is
a global variable being created?
For the same reason - when you do this.a++ you are creating and incrementing a global variable a by one.

Do not modify context even using a function that modifies the context

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?

difference in defining functions : JavaScript [duplicate]

This question already has answers here:
var functionName = function() {} vs function functionName() {}
(41 answers)
Closed 9 years ago.
Do we have any difference between the two mentioned function declaration in JavaScript
//Declaration 1
var foo = function(){
// code goes here
}
and
//Declaration 2
function foo(){
// same code here
}
When i tried to use foo's definition as a class to create other objects
var newObj = new foo();
The Declaration 2 worked but Declaration 1 did not allow me to create and object of this type
this is a function expression:
//Declaration 1
var foo = function(){
// code goes here
}
The func expression in this case is anonymous but assigned to a var foo.
for reference
This is a labeled function :
//Declaration 2
function foo(){
// same code here
}
There's not really any great reason to do expression to var. You
should always try to use labeled statements for constructors,so you
can identify an object's 'type' via its constructor.
people mostly use this where hoisting is needed.Hoisting simply means
calling something before it is defined.
Very very simple example:
foo(); // alerts 'hello'
function foo() {alert('hello');}
V/s
foo(); // throws an error since foo is undefined
var foo = function() {alert('hello');}
First creates a local variable that is assigned a function to. The second declaration creates a function. In first case there is no function to be used for the clients. This is why you can not create objects.
Check this fiddle. It is allowing both declaration:
//Declaration 1
var foo1 = function(){
alert('Declaration 1');
}
//Declaration 2
function foo(){
alert('Declaration 2');
}
var b= new foo1();
var a=new foo();
You can create object of function. here in your case declaration 1 consider foo is a variable so you can not create object of any variable that is why Declaration 2 worked and Declaration 1 did not allow you.
The first one creates an anonymous (nameless) function and assigns it to a variable called foo. The second one declares a function with the name foo. Usually those two forms can be used pretty interchangeable but there are still some differences. The following two are the main differences that come to my mind. The first one might be responsible for what you are experiencing:
Hoisting
In the second example, the complete function definition will be hoisted up to the top of the current scope. So when you write:
var a = new A();
function A() {}
JavaScript will interpret this as:
function A(){}
var a;
a = new A();
...and your code will work fine.
In the first example however, only the variable declaration will be hoisted up. The function body stays where it is. So this:
var a = new A();
var A = function(){};
will be interpreted as this:
var a, A;
a = new A();
A = function(){};
which will lead to an error, since A is still undefined by the time you try to create an instance.
The name property
As I said, the first one creates an anonymous function. That means, if you try to access the name property of that function it will return an empty string:
var A = function(){};
console.log(A.name) //{empty string}
In the second example, your function has the actual name A:
function A(){}
console.log(A.name) //A

Definition vs initialization

What's the difference between declaration, definition and initialization? Example:
// Is this a declaration?
var foo;
// Did I defined object in here (but it is empty)?
var foo = {};
// Now that object is initialized with some value?
var foo = {first:"number_one"};
The first example is a declaration. You have declared a variable with the identifier foo. You haven't given it a value yet, so it will be undefined:
var foo;
console.log(foo); //undefined
The second example is a declaration and an assignment. You have assigned an empty object literal to the variable with the identifier foo. As noted in the comments, this is effectively short for:
var foo;
console.log(foo); //undefined
foo = {};
console.log(foo); //Object
The third example is another declaration and another assignment. You have assigned a different object literal to foo.
Edit (see comments)
The behaviour of your code is slightly different depending on whether you intended each example to run as an independent program, or as written (one program).
If you treat is as it's written:
Because variable declarations in JavaScript are hoisted to the top of the scope in which they appear, redeclaring variables has no effect. So the first line declares a variable foo.
The second line assigns an empty object literal to foo, and the third line assigns a different object literal to foo. Both of these assignments apply to the same foo.
What effectively happens is this:
var foo;
foo = {}; //No `var` keyword
foo = {first:"number_one"}; //No `var` keyword
If you treat each line as a separate program:
The first program declares a variable named foo. It's value is undefined.
The second program declares a variable named foo, and then assigns an empty object literal to it.
The third program declares a variable named foo and then assigns an object literal with one property to it.
You got it right.
var foo; // Is this a declaration ?
Yes, you declared that there's a variable named foo, but didn't define foo (so foo is undefined).
var foo = {} // Did I defined object in here (but it is empty) ?
Yes, now you "defined" foo... it has a value, it is no longer undefined. var foo = 5 also counts as "defining" it.
var foo = {first:"number_one"} // Now that object is initialized with some value ?
You could say that it's "initialized," but that's really just semantics. "Declared" and "defined" are a bit more meaningful.
Run the code below:
var foo;
console.dir(foo);
var foo = {};
console.dir(foo);
var foo = {first:"number_one"};
console.dir(foo);
When you declare a variable with var foo; you actually ensure that it will belong to the scope where you've defined it. What you call definition and initialization is in fact a value assignment.
Consider following piece of code as an example:
(function () {
// definition
var foo;
function assignFoo(x) {
// assignment
foo = x;
}
assignFoo(5);
console.log(foo);
})();
To say, you're not always supposed to assign value within the scope of definition. But it is the most common use case which is usually accomplished with var foo = 5.
Thats it.

Refering to the container object inside event functions

I have code like this
var MyObj = {
f1 : function(o){ o.onmousedown = MyObj.f2;},
f2 : function(){ MyObj.f1(); }
}
I would like to know how to refer to MyObj without hardcoding it (i.e. this), so I can change object name without changing the code.
I am interested only in litteral object notation.
EDIT:
I didn't get it right. One of the functions was actually onmousedown event, so this wasn't working in it... This will refer to the object that rised event. I wonder is it still possible to refer to MyObj in such case.
Use this.
Eg:
var MyObj = {
f1 : function(){ ... },
f2 : function(){ this.f1(); }}
One of the functions was actually
onmousedown event, so this wasn't
working in it... This will refer to
the object that rised event. I wonder
is it still possible to refer to MyObj
in such case.
One way follows, though it may not be very useful in this case.
var baz = (function(){ // fake a scope
var foo; // foo will exist in the next statement
foo = { bar: function(){ return foo } };
return foo;
})();
The function wrapper, which is executed immediately, acts to keep variables scoped in that block (later versions of JS by Mozilla have improved scoping syntax, but I'm assuming that's not an option). In this simple example, foo is returned and used as the value for baz, but if you were really doing an assignment and didn't care if foo stayed around, then you'd only need the second two lines. But if it were part of a larger expression, then this idiom might come in handy.

Categories