JavaScript losing "this" object reference with private/public properties - javascript

I have the following error when running the page below:
"this.testpublic is not a function"
test = function() {
var testprivate = function() {
this.testpublic();
}
this.testpublic = function() {
console.log('test');
}
testprivate();
}
new test();
Apparently when testprivate is called, "this" starts pointing to "window" instead of the object.
Shouldn't JavaScript preserve "this" context when within the same object?

You need to manipulate the context when calling testprivate. You can use function.call to override the scope of the function. Try this:
test = function() {
var testprivate = function() {
this.testpublic();
}
this.testpublic = function() {
console.log('test');
}
testprivate.call(this);
}
new test();

The problem is that this actually never was referring to the test object to begin with. It was always referring to the nearest enclosing object -- which in this case is window.
test = function() {
var testprivate = function(say) {
console.log('test', say);
}
this.testpublic = function(say) {
testprivate('test', say);
}
testprivate();
}
x = new test();
This works because, as I understand it, this is determined at call time -- and it is locked into the nearest "enclosing" object*, unless call() or apply() is used.
* There is probably a much better word for this, but I don't know it off the top of my head. If someone knows, please enlighten us all :-)

No, it shouldn't. The function merely defines scope.
When you call foo.bar() then this (inside bar()) is foo. Since there is no explicit foo in this case, it is window by default.
(this is handled differently when the new keyword is in play, but it isn't for that call)

It is as Sean says: you aren't actually creating a new reference to an object (creating a this context), because you are simply calling the constructor - not utilizing the constructor to create a new object. If you use the new keyword, it works just peachy.
Since the scope of test() is window when you call it, any function called from within test() will execute in the window scope.
By using the new keyword, you are allocating a new object to memory - and creating a new scope.
For example, try this in firebug:
var myFunction = function() {
this.memberVariable = "foo";
console.log(this);
}
myFunction();
console.log(window.memberVariable);
var myObject = new myFunction();
console.log(myObject.memberVariable);
You will see this result:
Window stats
foo
Object { memberVariable="foo"}
foo
The Function base object has a method, call(), which as outlined by Craig, allows you to explicitly specify which scope the function should run in:
var myFunction = function() {
this.memberVariable = "foo";
}
myFunction.call(myFunction);
console.log(myFunction); // "Function()"
console.log(myFunction.memberVariable); // "foo"
This is, however, not the preferred way of doing things, as you aren't actually creating a new object here, and typeof myFunction will still return "function" instead of "object" - when you really just wanted to create an object.

Related

Arrow function and this inside a constructor function

I have read this paragraph about the this keyword : https://bonsaiden.github.io/JavaScript-Garden/#function.this
In this first case this refers to global objet, and it seems totally normal because when we have an arrow function, it automatically bind this with the one in the outer scope.
var obj = {
foo : () => console.log(this)
}
console.log(obj);
obj.foo()
However, I'm not able to explain the following behavior :
function bar(){
this.foo = () => console.log(this)
}
var obj = new bar()
console.log(obj);
obj.foo()
Now, this refers to obj instead of global. Why is that ? It seems to me that using the new keyword with the constructor function should return an object obj which is exactly identical as the one in the first example. And so the arrow function should have a this which refers to global and not to obj. Could you explain to me what's happening in the second case please ?
Functions -> No separate this
Until arrow functions, every new function defined its own this value (a new object in the case of a constructor, undefined in strict mode function calls, the base object if the function is called as an "object method", etc.). This proved to be less than ideal with an object-oriented style of programming
Read more about the new keyword here
The constructor function ... is called with the specified arguments, and with this bound to the newly created object.
The bar() constructor defines this as itself.
Although I myself am far from good with objects (need to work on that), I think that when you do const test = new Test() you initialize a new object. That way, the scope(?) of this references only to the newly created object, thus why you do this.foo and later on you reference to that foo property by using obj.foo. On the other hand, when you just do const obj = { .... }, you don't actually initialize a new object, so the this goes straight to the global object - the window. So, const test = new Test creates a new object, while using only const obj = {} is not a new object and this by default goes to the window object.

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?

Which is safer - using a self or this?

Is it safe to use the keyword "this" to create new Locker? I am afraid that "this" may point to something else at the runtime. I am new to JavaScript and closures.
var Employee = function() {
this.initialize.apply(this, arguments);
};
_.extend(Employee.prototype, {
initialize : function(opts) {
this._locker = new Locker({
employee : this
});
// OR
var self = this;
this._locker = new Locker({
employee : self
});
}
});
Looking at this code in particular:
this._locker = new Locker({
employee : this
});
Assuming that this already points to the right object, the above doesn't introduce a new scope; it would be the same as writing:
var options = {
employee : this
};
this._locker = new Locker(options);
You don't need to use self in this case.
You will have seen self used when someone wishes to pass the value of this into a different scope as a closure.
var self = this;
var myFunc = function() {
// do something with self (aka this)
};
In the example above this inside myFunc won't be known until the function is invoked - google 'dynamic vs static scoping' - and it won't be the 'this' from outside of the function. That this is passed through as self in my example.
Note: that you don't have to use self any other variable name will do.
In your example you aren't attempting to pass this into a different scope so it should be fine.
Both snippets act the same.
The value of this is determined by how a function is called, so you are right in that this may point to something else at runtime.
However, once initialize has been called the value of this for that call has already been set. So:
var self = this;
this._locker = new Locker({
employee : self
});
Just adds an intermediate step, assigning this to a temporary variable (see Jack's) answer
Your safer bet would be to use "this," since you are using apply and passing "this." Apply will force "this" keyword to be the thisArg that you passed to the function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
"self" is set to the Window object earlier in the initialization, but I don't think it changes after, unless you specifically change it.
Is it safe to use the keyword "this" to create new Locker?
Yes.
> var Employee = function() {
> this.initialize.apply(this, arguments);
> };
Within a function called with new (i.e. called as a constructor), this will always point to the new instance. Using apply means that arguments is not passed as an Object, but as a sequence of values. So I think you should be doing:
function Employee () {
this.initialize(arguments);
}
Note that function declarations are less code and more reliable than function expressions.
> _.extend(Employee.prototype, {
> initialize : function(opts) {
Since you are calling this with apply and using arguments as the parameter object, the arguments are passed individually by value. So opts will be the first value of the arguments originally passed to the Employee constructor, the others will be available as members of this new function's arguments object.
>
> this._locker = new Locker({
> employee : this
> });
> }
The value of this is set when a function is called (or by bind). In this case, initialize is intended to be called as a method of an instance so this will reference the instance. It could be called some other way so this references some other object (or any value if in strict mode), but the following has no effect on that.
This code doesn't make any difference to the value passed to Locker:
> var self = this;
> this._locker = new Locker({
> employee : self
> });
You seem to be trying to avoid a closure, but there is no closure here to avoid. Closures aren't caused by a function call, but by functions returning other functions that are created within them (through declarations or expressions). These functions continue to have access to the outer function's lexical environment after they have completed, e.g.
var foo = (function() {
var bar = 'bar';
return function(){ return bar;};
}());
foo(); // bar
The function foo has a closure to the variable bar declared in an outer function. No other function can access bar to read or set its value, it's only available to foo (this is how private members are emulated in javascript).
Where you run into trouble is where the value of the variable held in the closure is unexpectedly changed after the closure has been formed. That will not happen in the original code.

JavaScript global object?

Does the value of "this" refer to the global object or the object "o" in the program below?
More importantly, what code could I run to test what the reference of "this" is?
function F() {
function C() {
return this;
}
return C();
}
var o = new F();
It refers to the global object (window).
Edit: Actually, it will refer to both, the global object and o, because they are the same. o will have a reference to the object returned from F() which is the object returned from C() which is the window object ;)
You can call console.log(this) to find out which object it refers to. It should give you a listing of all the methods of the object on the console and you should be able to infer from this which object it is.
For this to work in Firefox, you need Firebug. Don't know for IE.
Update:
#Anurag already showed you how to explicitly set this. If you just want to refer to this of a higher scope, you have to assign it to a variable explicitly. Example:
function F() {
var that = this;
function C() {
console.log(that);
}
C();
}
this refers to the global object in your program. To get this to reference the instance of F, try,
function F() {
function C() {
return this;
}
return C.call(this); // call C with the object of F as a context
}
var o = new F();
On Chrome, you could simply enter the variable to inspect, and its value will get logged. It's similar to doing a console.log(object), but much easier to work with. Here's a screenshot of running this code sample in Chrome. The value of the last statement o is automatically printed, and I printed it once again, just to be sure. It logged DOMWindow which refers to the global window object on the browser.
To add to the other answers:
When a function is called, this is set depending on how it's called. If it's called with myfunc.call or myfunc.apply, then this is set to the first passed argument. If it's called in the 'dotted' form, i.e. myObject.myfunc() then this is set to whatever is before the dot.
There is an exception to this rule, which is that it's possible to bake the value of this in with bind, in which case it will be whatever has been bound. i.e. in var boundfunc = myfunc.bind(myobj); then any time boundfunc is called, it would be like calling myfunc but with this referring to myobj regardless of anything else. Here's an example that does that:
function F() {
var C = function() {
return this;
}.bind(this);
return C();
}
var o = new F();
If none of these cases are applicable, then this is always either the global object (window if you're in a browser), or, if you're in strict mode it's undefined.

this inside function

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

Categories