I thought that functions created using .prototype were supposed to be able to access local variables. Here is what I'm talking about:
function obj() {
var a = "String";
this.innerPrint = function() {
document.write("<p>" + a + "</p>");
};
}
obj.prototype.outerPrint = function() {
document.write("<p>" + a + "</p>");
};
var inst = new obj();
inst.innerPrint();
inst.outerPrint();
What I thought would happen is that both of these functions would do the same thing. But what actually happened is outerPrint doesn't have access to the variable a. Could someone explain to me how you get locals in a prototype function.
Here is a fiddle running this code:
http://jsfiddle.net/Wryte/mxXzg/
By the way, I want to use prototype functions because then each instantiation of the object doesn't have a copy of the function but they each point to the same one.
Of course not, you cannot access one function's locals from another function defined outside the first. It does not matter if the second is defined in the prototype property of the first. Each invocation of your obj function defines a new local a variable, so you cannot avoid having separate copies of the function that needs to access it.
I assume you actually require that variable to be a local and not an instance property, so one possible approach would be to have only a thin local wrapper around your function:
function obj() {
var a = "String";
this.wrapper = function() { outerPrint.call(this, a); }
this.innerPrint = function() {
document.write("<p>" + a + "</p>");
};
}
function outerPrint(a) {
document.write("<p>" + a + "</p>");
};
Again, I assume you have a more complex function in place of outerPrint, so this way you can avoid the duplication of a large function at the expense of duplication of a minimal wrapper. This way you retain the privateness of the a variable, while a public getter would allow external code to inspect its value.
UPDATE: On #Bergi's remark, I've modified the code to make outerPrint a local function in the same scope where the obj constructor is defined. No longer being on the prototype, it will not be directly callable for obj instances. Note that all of the code will need to be inside a function scope, in order to avoid a global outerPrint function.
If you want your variable a to be still accessible after the constructor has finished execution, change your code to
function obj() {
this.a = "String";
this.innerPrint = function() {
document.write("<p>" + this.a + "</p>");
};
}
obj.prototype.outerPrint = function() {
document.write("<p>" + this.a + "</p>");
};
Or define a getter if you don't want to provide direct write access :
function obj() {
var a = "String";
this.getA = function() {
return a;
}
this.innerPrint = function() {
document.write("<p>" + a + "</p>");
};
}
obj.prototype.outerPrint = function() {
document.write("<p>" + this.getA() + "</p>");
};
When you declare 'a' it's declared in the lexical scope of the obj()-function. All instance variables needs to be prototype'd as well, so insted of var a it should be declared as this.a.
No, it is a local variable. Scope rules are not bypassed because of a property named prototype.
The variable is accessible only from functions defined inside the constructor; they are called privileged because of that. Of course, when those are accessible as public methods you can call them from outside, ie.
Obj.prototype.outerPrint = function() {
this.innerPrint();
};
Related
I'm learning about anonymous closures and the module pattern. I understand that using a return object will expose some functionality of the module. However there have been some mentions of attaching some functionality to the window/global object.
I was wondering if attaching to the window was a more hacky way of doing a proper return, or had a legitimate use?
var speakingDog = (function() {
var dog = 'spot';
var says = 'woof';
function speak() {
return (dog + ' goes ' + says);
}
return {
speak: speak
}
})();
vs
(function() {
var dog = 'spot';
var says = 'woof';
function speak() {
return (dog + ' goes ' + says);
}
window.speak = speak;
})();
Adding attributes to window is equivalent to creating global variables (since that's actually what it does).
Your first example where you return the object on the other hand encapsulates everything and exposes it via speakingDog in the scope where the code runs. That's much cleaner of course, since you don't create rather meaningless (speak()) globals.
I am unsure on how to call these functions such as inventoryCheck in a web browser (chrome) console when it seems not visible. Is there a way I can call this? Thanks!
Below is a snippet of a javascript file.
(function() {
var CC, addToBagCheck, addToCartError, addToCartRequest, addToCartSuccess, availableSizes, displayCorrectShoe, inventoryCheck, isValidJSON, processInventory, selectSize, showBuy, showError, showSoldOut,
slice = [].slice,
bind = function(fn, me) {
return function() {
return fn.apply(me, arguments);
};
};
inventoryCheck = function() {
return availableSizes(function(product) {
return processInventory(product);
});
};
window.captchaResponse = function(response) {
$('#captcha').addClass('checked');
$('#flashproductform').append('<input class="captcha-duplicate" type="hidden" name="x-PrdRt" value="' + response + '">');
return addToBagCheck();
};
}).call(this);
You cannot. inventoryCheck is defined inside a closure. In order to call them globally (like in the console), you must define them on the window object. Since your closure appears to have window as its context (by calling it using this as context), then you can define inventoryCheck like:
this.inventoryCheck = function(){...}
Note that defining stuff on the global object is a bad idea. Consider attaching everything to a single global object you own. This reduces your footprint on the global object to just a single object. The following pattern is better:
;(function(ns){
ns.inventoryCheck = function(){...}
// the rest of the code
})(this.myGlobal = this.myGlobal || {});
// Usage
myGlobal.inventoryCheck(...);
I get confused on a JavaScript this reference situation.
I am working on a code that I declare function inside an object method. (The reason is to tidy up code inside an object method, while keeping the functions private to the method.)
The following is an experiment to re-produce my problem.
I found that the this inside greeting function refers to the window scope instead of person scope.
var person = {
nickname: "Makzan",
sayHi: function() {
console.log(this);
var greeting = function() {
console.log(this);
return "Aloha " + this.nickname;
}
console.log(greeting());
}
}
person.sayHi();
(same code in jsfiddle: http://jsfiddle.net/makzan/z5Zmm/)
And this is the log result in browser:
> Object
> Window
Aloha undefined
In JS, I know that this reference is tricky. And I can change the scope by using .call method to make this code works.
var greeting = (function() {
console.log(this);
return "Aloha " + this.nickname;
}).call(this);
However, I am curious to know why by default the this refer to window scope inside the greeting method?
Thanks in advance for all your help.
this has nothing to do with scope. It is determined by context.
greeting() calls the function with no context, so this is the default object (window in a browser).
The this, references is not related to scope, it depends on the calling context.
As per the MDN doc,
In general, the object bound to this in the current scope is
determined by how the current function was called
Try person.nickname, this refers to the var greeting in your case
If we modify your code a little, we can see that this works:
var person = {
nickname: "Makzan",
greeting: function () {return "Aloha " + this.nickname;},
sayHi: function () {return console.log(this.greeting());}
}
person.sayHi();
So we may conclude the reason that this doesn't:
var person = {
nickname: "Makzan",
sayHi: function () {var greeting = function () {return "Aloha " + this.nickname}; console.log(greeting()); }
};
person.sayHi();
is because for greeting() to have the this context of the person object, it must be explicitly declared as a direct property of the person object.
I can't seem to get my head around a specific case of scoping for JavaScript variables. Different from other examples and questions I have found, I am interested in the scoping for nested functions.
I've set up an example at this JSFiddle. The relevant part is the following:
function MyObject() {
var self = this;
var a = 1;
this.b = 2;
var innerMethod = function() {
//1 and 2: direct reference
logMessage("a = " + a); // a = 1
//logMessage("b = " + b); // Error: b is not defined
//3 and 4: using this
logMessage("this.a = " + this.a); // this.a = undefined
logMessage("this.b = " + this.b); // this.b = undefined
//5 and 6: using self
logMessage("self.a = " + self.a); // self.a = undefined
logMessage("self.b = " + self.b); // self.b = 2
}
}
Now, I understand that a reference to a directly works.
I also understand that messages 3 and 4 (this.a and this.b) will fail because this refers to the internal function. I also understand that line 6 works because I save the reference to the original object.
What I do not understand is:
why aren't messages 1 and 2 working alike?
why aren't messages 5 and 6 working alike?
The a variable is just that, a variable. It's visible in the scope of innerMethod (which is just a nested function), as a, which is how it was declared (ie. JavaScript has lexical scoping rules, inner functions can see variables of the functions they're defined inside of).
this isn't the same as the local scope of the MyObject constructor.
You've seen that self is an alias for this of MyObject, and that innerMethod has overwritten this in its own scope. Still, since this is not an alias for function scope, neither self.a nor this.a will ever work here.
For a more rigorous explanation of lexical scoping you can e.g. start at wikipedia: http://en.wikipedia.org/wiki/Scope_(computer_science)
You can read about the execution contexts and identifier resolution rules in the ECMA standard http://es5.github.com/#x10.3
It's a problem with scope, when functions are created they save their surroundings (including variables).
So when innerMethod is created, it can see variables self and a.
An important concept is that the scope is created when the function is declared, instead of when it is called.
In your case 1, b is not being declared (the this object is not the same).
In cases 5 and 6, you did not create self.a.
The main reason is that self is not equal to this in scope of innerMethod. this is a keyword to reference the owner of the function. For innerMethod, it is NOT a instance method, it belongs to the Window.
function MyObject() {
var self = this;
var innerMethod = function() {
alert("inner method, self == this?: " + self == this); // false
alert("inner method: " + this); // [object Window]
alert("closest constructor name of in prototype chain ?: "+ this.__proto__.constructor.name); // Window
}
this.outerMethod = function(){
innerMethod();
alert("outer method: " + this); // [object MyObject]
alert("closest constructor name in prototype chain?: "+ this.__proto__.constructor.name); // MyObject
}
}
var o = new MyObject();
o.outerMethod();
You can play at here
I am a beginner in js, and am puzzled by the following code:
Foo = function(arg) {
this.arg = arg;
};
Foo.prototype = {
init: function () {
var f = function () {
alert("current arg: " + this.arg); // am expecting "bar", got undefined
}
f();
}
};
var yo = Foo("bar");
yo.init();
I was expected to get "current arg: bar", but got "current arg: undefined". I noticed that by copying this.arg into a "normal" variable first, and refering this variable in the closure works:
Foo.prototype = {
init: function () {
var yo = this.arg;
var f = function () {
alert("current arg: " + yo); }
f();
}
};
Am I doing something wrong, got wrong expectations, or does it fall into one of the js WTF ?
Vanilla functions will be run with this referring to window. Your second piece of code is a perfect example of how to work around this problem using closures.
(You can also use call and apply to call a function with a particular context.)
It depends on how the function was invoked.
If invoked with keyword new then this refers to the object being constructed (which will be implicitly returned at the end of the function).
If invoked as a normal function, this refers to the global window object.
Example:
// Constructor for Foo,
// (invoke with keyword new!)
function Foo()
{
this.name = "Foo" ;
}
myFoo = new Foo() ;
alert( 'myFoo ' + myFoo.name + '\n' + 'window: ' + window.name ) ; // window.name will be empty
// now if we invoke Foo() WITHOUT keyword NEW
// then all references to `this` inside the
// function Foo will be to the
// __global window object__, i.e. the global window
// object will get clobbered with new properties it shouldn't
// have! (.name!)
Foo() ; // incorrect invokation style!
alert( 'myFoo ' + myFoo.name + '\n' + 'window: ' + window.name ) ;
JavaScript doesn't have "constructors" per se, the only way JavaScript knows that your function is actually a "constructor" is invokation style (namely you using keyword new whenever you invoke it)