Value of this in protoypal object in JavaScript - javascript

I'm trying something like this:
(function() {
var Foo, foo;
Foo = function(proto) {
var obj, privateMethod, publicMethod;
privateMethod = function() {
return console.log("private", this);
};
publicMethod = function() {
console.log("public", this);
return privateMethod();
};
obj = Object.create(proto);
obj.bar = publicMethod;
return obj;
};
foo = new Foo({
baz: "dooz"
});
foo.bar();
}).call(this);
Obviously this is the object itself when publicMethod is called, but is set to the global object in the privateMethod. I know it can be solved by changing:
return privateMethod();
to:
return privateMethod.call(this);
I know that this get's lost when a function is nested in a function, but did not expect that case here. Do I encounter this JavaScript bug here or is there something that I simply do not understand yet?

Context (this), in javascript, is set by how a function is called, and is in no way a property of the function itself.
obj.bar = function() { console.log(this) };
obj.bar() // obj
obj['bar']() // obj
// But break the function off the object, and this changes
fn = obj.bar
fn() // window
What this example shows us is that the the dot syntax there sets this. Think of obj.bar() is syntax sugar for obj.bar.call(obj).
So your public method gets the right this, because of how it's called in external code.
foo.bar();
But your private method is invoked with no receiver at all.
return privateMethod();
So no context is assigned, and it defaults to the global object.
So given you are creating these functions in the constructor, you have some flexibility.
You could assign the proper value of this in the constructor to something else, and use that in your private functions. (Likely the best option)
var self = this;
privateMethod = function() {
return console.log("private", self);
};
Or if your JS target engine support Function.prototype.bind (not all do, sadly) you could do:
privateMethod = function() {
return console.log("private", this);
}.bind(this);
Which will return a function that has an assigned context, no matter what.
Or you could bind it manually yourself.
_privateMethod = function() {
return console.log("private", this);
}
Foo = function(proto) {
privateMethod = function() {
_privateMethod.call(this);
}
}

You're calling foo.bar(). This means the function bar() is called on foo, meaning this is foo inside bar().
In your case foo is a Foo object obj, and bar() is publicMethod.
When publicMethod() calls privateMethod(), there's no context, so this becomes the global this (window).

Related

Why the execution context ("this") of prototypical function is wrong in this example?

Prototypical function bar is executed elsewhere, in a Node.js environment (where bind should be available). I want this inside bar() function to be the instance of my object:
var Foo = function (arg) {
this.arg = arg;
Foo.prototype.bar.bind(this);
};
Foo.prototype.bar = function () {
console.log(this); // Not my object!
console.log(this.arg); // ... thus this is undefined
}
var foo = new Foo();
module.execute('action', foo.bar); // foo.bar is the callback
... why bar() logs undefined and this is not my instance? Why the execution context was not changed by the bind call?
Function.bind returns a value - the newly bound function - but you just discard that value. Function.bind does not alter this (that is, its invocation context), nor does it alter its arguments (this).
Is there another way to get the same result?
Doing it inside of the constructor function is actually wrong, because bar lives on Foo.prototype, so binding it to any one instance of Foo would break this for all other Foo.bar calls! Bind it where you mean it:
module.execute('action', foo.bar.bind(foo));
Or – maybe even simpler – don't define bar on the prototype at all:
var Foo = function (arg) {
this.arg = arg;
function bar () {
console.log(this);
console.log(this.arg);
}
this.bar = bar.bind(this);
};
var foo = new Foo();
module.execute('action', foo.bar);

JS: Passing a scope as argument, binding it to a function that will be returned

Is it possible to define a function in the scope of a parent function and bind an argument passed through the parent function as its scope before returning it?
Here is an example:
var myObject = {
foo: "bar"
};
var myFunction = (function() {
return function() {
return this.foo;
};
}).call(myObject);
myFunction.call(myObject); // I'd like to bind myObject as this does ...
myFunction(); // ... but I'd like to do it before invoking it, without .call() or .apply()
Or another complex example, that describes what I'm trying to do:
var createMyCopy = function(original, self) {
var copy;
eval("copy=" + original.toString());
console.log(copy()); // returns undefined
};
(function() {
var self = "Hello world",
myFunction = function() {
return self;
};
console.log(myFunction()); // returns "Hello world"
createMyCopy(myFunction);
})();
I'm trying to create a copy of a function, so that I can make changes to it without changing the original one, but I'd like to have the variables that are defined in the original one in the copy as well...
Do you mean like this?
var myObject = {
foo: "bar"
};
var myFunction = (function() {
var self = this;
return function() {
return self.foo;
};
}).call(myObject);
I think you're getting scope and context mixed up in your question.
I think you mean this:
var myFunction = (function(obj) {
return function() {
return obj.foo;
};
})(myObject);
The immediately invoked function expression is passed myObject and returns a new function in which that parameter is bound as the variable obj.
I'm not sure what you mean, but you can do this:
var myObject = {
foo: "bar"
};
function myFunction() {
return this.foo;
}
console.log(myFunction.apply(myObject)); // bar
The first argument of apply is the context (ie. what this refers to). The second argument of apply is an array of arguments (but I've omitted that here as there are no arguments).

Javascript module pattern, scope and "this"

I'm trying to wrap my head around building a custom JavaScript library. I've read a lot about the module pattern, and also read Crockford's articles on private and public members. I know what is an immediately invoked function expression and why we do stuff like
var myLib = (function() {
}())
However, I'm still a little lost in some cases regarding scope and closures in general. The concrete problem I have is:
Why does the following example alert DOMWindow, rather than the myLib object?
http://jsfiddle.net/slavo/xNJtW/1/
It would be great if you can explain what "this" refers to in all of the methods in that example and why.
Inside any function declared (anywhere) and invoked as follows this will be window object
function anyFunc(){
alert(this); // window object
}
anyFunc();
var anyFunc2 = function(){
alert(this); // window object
}
anyFunc2();
If you want to create private functions and access the instance of 'myObject' you can follow either of the following methods
One
module = (function () {
var privateFunc = function() {
alert(this);
}
var myObject = {
publicMethod: function() {
privateFunc.apply(this); // or privateFunc.call(this);
}
};
return myObject;
}());
module.publicMethod();
Two
module = (function () {
var _this; // proxy variable for instance
var privateFunc = function() {
alert(_this);
}
var myObject = {
publicMethod: function() {
privateFunc();
}
};
_this = myObject;
return myObject;
}());
module.publicMethod();
These are solutions to your issue. I would recommend using prototype based objects.
EDIT:
You can use the first method.
In fact here myObject is in the same scope as privateFunc and you can directly use it inside the function
var privateFunc = function() {
alert(myObject);
}
The real scenario were you can use a proxy for this is shown below. You can use call also.
Module = function () {
var _this; // proxy variable for instance
var privateFunc = function() {
alert(this + "," + _this);
}
this.publicMethod = function() {
privateFunc(); // alerts [object Window],[object Object]
privateFunc.call(this); // alerts [object Object],[object Object]
}
_this = this;
return this;
};
var module = new Module();
module.publicMethod();
You need to explicitly state that myPrivateMethod is a member of myLib:
function MyLib ()
{
this._myPrivateField = "private";
this._myPrivateMEthod = function ()
{
alert(this); // Alerts MyLib function;
}
}
var libObject = new MyLib();
Just remember that without using enclosure techniques, nothing in JavaScript is ever truly private!
A better way to do the above is like so:
function MyLib(instanceName)
{
this.name = instanceName;
}
MyLib.prototype.myPrivateFunction()
{
alert(this);
}
To call your method after that:
var libObject = new MyLib();
libObject.myPrivateMethod(); // Alerts info about libObject.
The thing to remember about the module pattern is that it runs once and completes. The methods that are still available to be called are the closures. At the time of creating module, "this" refered to the window and was replaced by its value.
In your linked fiddle, the "this" keyword is never changed by a "new" keyword or other context change, so it still refers to the global window object.
edit: clarification

jQuery-style function that can be accessed like an object

I am creating an AJAX API for a web service and I want to be able to call jQuery-like accessors.
jQuery seems to be able to execute 'jQuery' as a function, but also use it to directly access the object that is the result of the function EG:
jQuery();
jQuery.each({});
This is the trick that I can't seem to pull off:
myAPI('foo'); //output: 'foo'
myAPI('foo').changeBar(); //output: 'foo' 1
myAPI.changeBar(); //Error: not a function
I have seen the answers to similar questions, which are helpful, but don't really answer my question.
#8734115 - Really interesting, but you can't access the methods that were set by f.prototype.
#2953314 - Uses Multiple operations to create object instead of a single function.
here is my code:
(function(window) {
var h = function(foo) {
// The h object is actually just the init constructor 'enhanced'
return new h.fn.init(foo);
};
/**
* Methods defined at protoype.
*/
h.fn = h.prototype = {
constructor: h,
init: function(foo) {
console.log(foo);
return this;
},
splice : function () {},
length : 0,
bar : 0,
changeBar : function() {
this.bar++;
return this.bar;
}
};
h.fn.init.prototype = h.fn;
//Publish
window.myAPI =h;
}( window));
I'm sure I'm missing something simple :(
What jQuery is doing there is using jQuery as both a function and as a pseudo-namespace. That is, you can call jQuery: var divs = jQuery("div"); and you can use properties on it, e.g.: jQuery.each(...);.
This is possible because in JavaScript, functions are first-class objects, and so you can add arbitrary properties to them:
function foo() {
alert("Foo!");
}
foo.bar = function() {
alert("Bar!");
};
foo(); // "Foo!"
foo.bar(); // "Bar!"
That's literally all there is to it.
Within the call to bar, this will be the foo function (because this is determined entirely by how a function is called, not where it's defined). jQuery doesn't use this to refer to itself (usually it uses this to refer to DOM elements, sometimes to other things like array elements; when referring to itself, since it's a single thing, it just uses jQuery).
Now, you might want to ensure that your functions have proper names (whereas the function I assigned to bar above is anonymous — the property has a name, but the function does not). In that case, you might get into the module pattern:
var foo = (function() {
function foo() {
alert("Foo!");
}
function foo_bar() {
alert("Bar!");
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
That pattern also has the advantage that you can have private data and functions held within the scoping function (the big anonymous function that wraps everything else) that only your code can use.
var foo = (function() {
function foo() {
reallyPrivate("Foo!");
}
function foo_bar() {
reallyPrivate("Bar!");
}
function reallyPrivate(msg) {
alert(msg);
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
reallyPrivate("Hi"); // Error, `reallyPrivate` is undefined outside of the scoping function
In your code, you're assigning things to the prototype property of the function. That only comes into play when the function is called as a constructor function (e.g., via new). When you do that, the object created by new receives the function's prototype property as its underlying prototype. But that's a completely different thing, unrelated to what jQuery does where it's both a function and a pseudo-namespace.
You do not need any of that weirdness, to use stuff like $.each
you just attach functions to the function object instead
of the prototype object:
function Constructor() {
if (!(this instanceof Constructor)) {
return new Constructor();
}
}
Constructor.prototype = {
each: function() {
return "instance method";
}
};
Constructor.each = function() {
return "static method";
};
var a = Constructor();
a.each(); //"instance method"
Constructor.each(); //"static method"

Why won't this object's prototype's init function run

I use the following function for creating new objects.
function newObj(o) {
var params = Array.prototype.slice.call(arguments,1);
function F() {}
F.prototype = o;
var obj = new F();
if(params.length) {
obj.init.apply(obj,params);
}
return obj;
}
And it works well most of the time. However one of my base "classes" is now defined as inheriting from another base class
SPZ.EditablePuzzle = function () {
// function and variable definitions
return {
///some methods and properties
}
}();
SPZ.EditablePuzzle.prototype = SPZ.Puzzle;
Now when I use newObj() to create a new SPZ.EditablePuzzle the init function is not defined even though it is defined in SPZ.Puzzle and I make sure EditablePuzzle runs after Puzzle
Why won't my newObj function find the init function? Shouldn't it automatically look in the prototype as soon as it fails to find it in the object itself?
I suspect the inheritance is not well set. try doing
SPZ.EditablePuzzle.prototype = new SPZ.Puzzle;
Might solve this problem, though I am not sure.
Concerning the problem:
function Foo() {
}
Foo.prototype.init = function() {
console.log('bla');
};
function FooBar() {
}
FooBar.prototype = Foo; // looks fishy...
var kitten = new FooBar();
console.log(kitten.init); // yields undefined, uh what?
The problem is, that in this case Foo itself gets assigned to the prototype property, when in fact you wanted to do:
FooBar.prototype = Foo.prototype
See the difference? Foo has no init property as it is defined on the prototype object.

Categories

Resources