Using local variables with "apply" in Javascript - javascript

Why "show" method is not able to access "text" variable here ?
// #constructor A
var A = function(){
//alerts some text variable
this.show = function(){
alert("Hello")
alert(text);
}
}
//#constructor B
var B = function(){
//local text variable
var text = "World";
A.apply(this); // "show" method will get attached to B
}
var obj = new B();
//now calling show of B's object.
obj.show(); //returns error.
//Expected output
alerts "Hello"
alerts "World"
//Actual output
alerts "Hello"
ReferenceError: text is not defined
Am I missing something here ?
Shouldn't the "text" variable be accessible to B's "show" method?

Unlike C++ or Java, Javascript doesn't have an implicit this.
If a function (like show) refers to this.foo, then only the value of this depends on how the function was called.
However, if show refers to a variable directly (like foo), then it can mean either:
a local variable, if it's defined using var at the function scope;
a variable from a closure, if the function is being defined inside another function that happens to define it with var (closure gets created at the moment of function definition),
a global variable otherwise.
In your case, the third case applies. show can't access text because it is defined in a totally unrelated scope.

You need to declare the text as property of B constructor this.text = "World"; something like this.
var A = function(){
//alerts some text variable
this.show = function(){
alert("Hello")
alert(this.text);
}
}
//#constructor B
var B = function(){
//local text variable
this.text = "World";
A.apply(this); // "show" method will get attached to B
}
var obj = new B();
//now calling show of B's object.
obj.show(); //returns error.

Related

Class loses "this" scope when calling prototype functions by reference

Can anyone explain to me why "b" returns undefined and how I can get around this problem? Why does the "this" scope get lost when I call prototype functions by reference?
MyClass = function(test) {
this.test = test;
}
MyClass.prototype.myfunc = function() {
return this.test;
}
var a = new MyClass('asd').myfunc();
var b = new MyClass('asd').myfunc;
// Returns "asd" correctly
console.log(a)
// Returns undefined??
console.log(b())
=== EDIT / SOLUTION ===
As plalx writes, the correct solution in my case is to use .bind(). So the result looks like this:
MyClass = function(test) {
this.test = test;
}
MyClass.prototype.myfunc = function() {
return this.test;
}
var a = new MyClass('asd').myfunc();
var b = new MyClass('asd'),
bfunc = b.myfunc.bind(b)
// Returns "asd" correctly
console.log(a)
// Also returns "asd" correctly!
console.log(bfunc())
You need to explicitely bind the this value if you want this behaviour.
var c = new MyClass('asd'),
b = c.myfunc.bind(c);
console.log(b());
By default, this will point to the leftSide.ofTheDot(); in an invocation, or simply the object on which the function was called.
Note: Calling b(); is the same as window.b();.
Binding every function to the object instance is possible but rather inefficient because functions will not get shared across instances anymore.
E.g.
function MyClass(someVal) {
var me = this;
me.someVal = someVal;
me.someFn = function () {
return me.someVal;
};
}
The line var b... is a function reference and you're not actually calling the function.
Here you are assigning to a variable a result of myfunc() function.
var a = new MyClass('asd').myfunc();
And here, you are asigning to b variable function reference, rather then runing it, and assign result to variable.
var b = new MyClass('asd').myfunc;
And finaly here:
console.log(b())
You trying to log result of function b and in that case b() isn't defined anywhere, only it is assigned reference to function.
Try this:
console.log(b); // It logs [Function]
But besides that, your question is hard to understand.
P.S. Use semicolons!

javascript unassigned default function parameters

In the following function:
foo = function(a){
if (!a) a = "Some value";
// something done with a
return a;
}
When "a" is not declared I want to assign a default value for use in the rest of the function, although "a" is a parameter name and not declared as "var a", is it a private variable of this function? It does not seem to appear as a global var after execution of the function, is this a standard (i.e. consistent) possible use?
It's a private variable within the function scope. it's 'invisible' to the global scope.
As for your code you better write like this
foo = function(a){
if (typeof a == "undefined") a = "Some value";
// something done with a
return a;
}
Because !a can be true for 0, an empty string '' or just null.
Yes, in this context a has a scope inside the function. You can even use it to override global variables for a local scope. So for example, you could do function ($){....}(JQuery); so you know that $ will always be a variable for the JQuery framework.
Parameters always have private function scope.
var a = 'Hi';
foo = function(a) {
if (!a) a = "Some value";
// something done with a
return a;
};
console.log(a); // Logs 'Hi'
console.log('Bye'); // Logs 'Bye'

When I declare a variable inside a function, which object is it a property of?

So when I declare a variable outside the scope of any function, it becomes a property of the window object. But what about when I declare a variable inside the scope of a function? For example, in the following code I can treat x as a property of window, i.e., window.x, but what about y? Is it ever the property of an object?
var x = "asdf1";
function test() {
var y = "asdf2";
}
test();
It becomes a property of the Variable object associated with the function call. In practice, this is the same thing as the function call's Activation object.
I don't believe that the Variable object is accessible to running JavaScript code, though; it's more of an implementation detail than something you can take advantage of.
Access all local variables is a related question here on SO.
In order to declare a JS variable a property of an object you need to either use the new Object(); method or the {} syntax.
var variableName = new Object();
var variableName = {myFirstProperty:1,myNextProperty:'hi',etc};
Then you can assign child objects or properties to said variable object
variableName.aPropertyNameIMadeUp = 'hello';
variableName.aChildObjectNameIMadeUp = new Object();
As such the new variable object is associated with a method if it is within the method call.
Cheers
See following example (I have copy from other question-answer) very nice:
// a globally-scoped variable
var a=1;
// global scope
function one(){
alert(a);
}
// local scope
function two(a){
alert(a);
}
// local scope again
function three(){
var a = 3;
alert(a);
}
// Intermediate: no such thing as block scope in javascript
function four(){
if(true){
var a=4;
}
alert(a); // alerts '4', not the global value of '1'
}
// Intermediate: object properties
function Five(){
this.a = 5;
}
// Advanced: closure
var six = function(){
var foo = 6;
return function(){
// javascript "closure" means I have access to foo in here,
// because it is defined in the function in which I was defined.
alert(foo);
}
}()
// Advanced: prototype-based scope resolution
function Seven(){
this.a = 7;
}
// [object].prototype.property loses to [object].property in the scope chain
Seven.prototype.a = -1; // won't get reached, because 'a' is set in the constructor above.
Seven.prototype.b = 8; // Will get reached, even though 'b' is NOT set in the constructor.
// These will print 1-8
one();
two(2);
three();
four();
alert(new Five().a);
six();
alert(new Seven().a);
alert(new Seven().b);

Scope of self-invocation function in Javascript

Why does self-invocation function inside a function don't get the scope of the outer function in JavaScript?
var prop = "global";
var hash = {
prop: "hash prop",
foo: function(){
console.log(this.prop);
(function bar(){
console.log(this.prop);
})();
}
};
var literal = {
prop: "object"
};
hash.foo();
// hash prop
// global
hash.foo.call(literal);
// object
// global
Looks like altering the scope of the outer function has no effect on the scope of the inner self-invocation function.
PS: The question is not about how to alter the scope of the inner function. But what is the proper explanation in the "Javascript language" perspective? Does all self executing functions have 'global' scope by default? If so, why?
Your problem is the this and what it references:
foo: function(){
console.log(this.prop);
(function bar(){
console.log(this.prop); <--- this does not reference to foo here, but instead it refers to the window object
})();
}
You need to keep a reference to the outer this:
foo: function(){
console.log(this.prop);
var that = this;
(function bar(){
console.log(that.prop); <--- tada!
})();
}
Update
Some explanation. It's all about how JavaScript determines the context when invoking a function.
function Test() {
this.name = "Test";
this.bar = function() { console.log("My name is: "+ this.name);}
}
function Blub() {
this.name = "Blub";
this.foo = function() { console.log("My name is: " + this.name);}
}
var a = new Test();
var b = new Blub();
// this works as expected
a.bar(); // My name is: Test
b.foo(); // My name is: Blub
// let's do something fun
a.foo = b.foo; // make an educated guess what that does...
a.foo() // My name is: Test
Huh? Aren't we referencing the method of Blub? No we're not. We are referencing the unbound function of Blub.
JavaScript binds on . (dots) and based on that it decides waht the value of this should be.
Since you're not calling your anonymous function on an object (therefore no .) it will make this reference to the global object, which is - in case of the browser - the window object.
Another example (one might think this would work):
var str = "Hello World";
var ord = str.charCodeAt; // let's make a little shortcut here.... bad idea
ord(0) // no dot...
Instead of the char codes that are in str we get the ones that are in the global object, of course that's not a string so charCodeAt calls toString on which results in "[object DOMWindow]"
You are not applying any object as the this context when you call the inner function, so it gets this set to window by default. If you wanted to call the closure with the same this as the outer function, you would have to do:
(function bar(){
console.log(this.prop);
}).call(this);
Or:
var that = this;
(function bar(){
console.log(that.prop);
})();

HTML JavaScript Include File Variable Scope

If I include a JavaScript file in my HTML page, do the variables declared in my JavaScript file also have scope in my <script /> tags in my HTML page? For example, in my included JS file, I declare a variable:
var myVar = "test";
Then inside my HTML page, what will this produce (if it's after my include script tag)?
alert(myVar);
If you declare the variable outside of any function as
var myVar = 'test';
or at any location as
myVar = 'test';
or
window.myVar = 'test';
It should be added to the Global Object (window) and be available anywhere as
alert(myVar);
or
alert(window.myVar);
or
alert(window['myVar']);
It will produce an alert containing "test".
All variables declared at the top level in JavaScript share the same scope. If you want to use variables in one file that won't clash with another, then you can use an anonymous function to introduce a new scope:
var myVar = "something else";
(function () {var myVar = "test"; alert(myVar)})();
alert(myVar);
edit: As BYK points out, you can expand this into something that resembles a full fledged namespace, by assigning an object literal:
var MyNamespace = (function () {
var myVar = "something";
return { alert: function() { alert(myVar) },
setVar: function(value) { myVar = value } }
})();
When you declare a variable or a function in your code, you're creating a property of window. Consider these examples:
var a = 'Cow';
alert(window.a); // Cow
alert(this.a); // Cow
alert(a); // Cow
If you declare a variable inside a function, your variable won't be accessible from outside of it unless you add it to the window object:
function lalala() {
alert(a); // still Cow
a = 'Pig'; // We're tired of cows by now. Let's make it a pig.
var b = 'Sheep';
}
lalala();
alert(a); // Pig
alert(b); // undefined, since b is declared in the lalala scope
Thus, your example would alert test.

Categories