I'm learning about angularjs and I keep noticing when a function is declared, most people usually make "this" into a var before modifying it. Why is that?
Code snippet below:
function NameService() {
var self = this; **THIS BLOCK. WHY??**
//getName returns a promise which when
//fulfilled returns the name.
self.getName = function() {
return $http.get('/api/my/name');
};
}
And at the bottom, the example uses self.getName. Why not just directly call this.getName?
Thanks
This is just a pattern that you can use. Generally it helps avoiding collisions of the 'this' keyword which is very common in the javascript 'world'.
Also helps with readability, so you can easier read your code.
Check out this example, where you can easily distinguish the public functions of the service and the local/private ones:
function NameService() {
var self = this; **THIS BLOCK. WHY??**
self.getName = getName;
self.setName = setName;
//getName returns a promise which when
//fulfilled returns the name.
function getName() {
return $http.get('/api/my/name');
};
function setName(){
//blablabla
}
function justAHelperFunction(){
//helper function, kind of inner function, a private function
}
}
In javascript this refers to the current object and the value of this in say a method depends how the function is invoked. When you pass a callback to a function call the context of this gets changed and inside the callback definition this doesn't refer to the object that has the method which further called the function with callback.
var person = {
firstName: 'John',
lastName: 'Doe',
printFullName: function () {
setTimeout(function () {
// here this doesn't point to the person object anymore
// as the callback passed to setTimeout was invoked by global window object
// so this points to window
console.log(this.firstName + ' ' + this.lastName);
}, 100)
}
}
To fix the above scenario where you expect this to be person you make an alias of the context capturing the reference in another variable. Here's the correct version of above method.
printFullName: function () {
var self = this;
// till now self == this
setTimeout(function () {
// here self still points to person whereas this is now pointing to window
console.log(self.firstName + ' ' + self.lastName);
}, 100)
}
Related
Im reading "Eloquent Javascript" book and I'm in the chapter "The secret life of objects".
And the author says:
"since each function has it's own bindings, whose value depends on
they way it is called, you cannot refer to the this of the wrapping
scope in a regular function defined with the function keyword.
i did not understand what does he mean by "wrapping scope", can you please explain and provide a simple example?
Wrapping scope of your function would be the scope where the function is defined.
e.g.
function outer() {
var outerThis = this;
return function inner() {
console.log(outerThis, this);
}
}
Here, inner function has wrapping scope = scope of outer. And, the inner function doesn't have access to the outer's this which is why we need to store it in a variable outerThis if we want to use it.
var innerFunction = outer.call({});
innerFunction();
If you do above on chrome console, This will print:
{}, // Caller of outer() (it was bound)
Window // Caller of inner()
Here is an example of how the use of "function" keyword will produce a function that does not have the same meaning to "this" as the containing scope has. You can overcome this by using an arrow function.
See also: https://medium.com/better-programming/difference-between-regular-functions-and-arrow-functions-f65639aba256
const container = {
name: "Bob",
sayName: function() {
console.log('say name root:', this.name);
const nestedWithFunctionKeyword = function() {
// Notice here that introducing "function" ruins the "this" reference. It no longer is referring to "container".
console.log('say name function:', this.name);
};
nestedWithFunctionKeyword();
// But we can re-bind "this" if we want.
nestedWithFunctionKeyword.call(this);
const nestedWithArrowSyntax = () => {
console.log('say name with arrow:', this.name);
};
nestedWithArrowSyntax();
},
};
container.sayName();
console.log('-----------------');
// Now lets look how how "the way you call the function" matters. Here we do not call the function within the context of "container" anymore, so the results change.
const sayNameRef = container.sayName;
sayNameRef();
this keyword refers to the object it belongs to, for example:
function diner(order) {
this.order = order;
this.table = 'TABLE 1';
this.eatHere = eatHere
this.goOutside = goOutside
function eatHere() {
// adding () instead of a function
// will use the scope of the object it self
setTimeout(() => {
console.log(`EAT HERE: eating ${this.order} at ${this.table}`);
}, 200);
}
function goOutside() {
// adding a new function scope inside the function
// will go outside the current object's scope
setTimeout(function () {
console.log(`EAT OUTSIDE: eating ${this.order} at ${this.table}`);
}, 200);
}
}
let obj = new diner("soup");
obj.eatHere(); // this order will be defined
obj.goOutside(); // this order will be undefined
Say I have an object constructor and a prototype method, like:
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function(){
console.log('my name' + this.name);
};
Elsewhere in my code, I've defined an instance of human:
let jeff = new Human('jeff');
and lastly I want to pass jeff.sayName as a callback to some other function, like (for a particularly trivial example)
function callFunction(callback) {
callback();
}
callFunction(jeff.sayName);
When I call callFunction(jeff.sayName) above, the context needs to be bound to jeff itself, like
callFunction(jeff.sayName.bind(jeff)). But this is clunky, and I'd rather not have to worry about this sort of logic every time I use this method as a callback.
An alternative would be to replace Human.prototype.sayName with something like
Human.prototype.createSayName = function(context){
return function() {
console.log(context.name);
};
};
and then define the function with
jeff.sayName = jeff.createSayName(jeff)
but this is a bit awkward, and I'd like to keep jeff agnostic to the methods it inherits from Human.prototype.
So ideally I'd like to handle this logic on Human.prototype itself, something like
Human.prototype.sayName.bind(WhateverObjectHoldsThisMethod)
but I'm not aware javascript has a way of doing this.
TL;DR I would like a way of binding an object's prototype method to whatever object inherits it, without having to do so every time I pass that method as an argument or every time I define a new object. Sorry if this makes little sense. Thanks!
Due to the way lexical environments, scope resolution, prototypal inheritance, and environment records work in JavaScript, what you're asking for is not possible without modifying the function which calls the callback function.
However, you could—instead of passing the Human#sayName reference as the call back—use an arrow function that in turn calls the Human#sayName reference you wish to call.
It's not perfect, but it's simple, clean, and readable.
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function(){
console.log('my name' + this.name);
};
let jeff = new Human('jeff');
function callFunction(callback) {
callback();
}
callFunction(_ => jeff.sayName());
For a better understanding of those fancy words I referenced earlier, and how they work in JavaScript, I would recommend reading section 8.1 of the ECMAScript 2017 Language Specification. Subsection 8.1.1.3 has the specific information you're looking for, but the rest of the section up to that point is necessary to understand that subsection.
Basically, when you pass Human#sayName to callFunction, you're passing the reference to the original sayName function, so you might as well be doing this: (pardon the pun)
function callFunction(callback) {
callback();
}
callFunction(function(){
console.log('my name' + this.name);
});
The content of the function is not evaluated until it is executed, which means by the time it is executed, the value of this has already changed. To add to the debacle, the original function has no knowledge of which instance you requested it through. It never actually exists on the jeff object. It exists in the prototype of the the function object, and when you perform the object property look up, the JavaScript engine searches the prototype chain to find that function.
You very well could get the behavior you're asking for, but not under the constraints you have laid out. For example, if the function does not have to exist on the prototype chain, and can instead exist on the instance (keep in mind that this creates a new function object for each instance, so it will increase cost), you could define the function in the constructor, then store a reference to the correct this using an identifier that will not be overwritten:
function Human(name) {
const _this = this;
this.name = name;
this.sayName = function(){
console.log('my name' + _this.name);
};
}
let jeff = new Human('jeff');
function callFunction(callback) {
const _this = { name: 'hello' }; // does not affect output
callback();
callback.call(_this); // does not affect output
}
callFunction(jeff.sayName);
This would be a safer option, because you know that _this will always refer to the object you're expecting it to refer to within the context of the constructor, all function objects defined within that function object will inherit the identifiers of their parent scope, and those identifiers will not be affected by the calling context.
Or, you could go one step further, and not rely on the value of this at all:
function Human(name) {
const sayName = function(){
console.log('my name' + name);
};
Object.assign(this, { name, sayName });
}
let jeff = new Human('jeff');
function callFunction(callback) {
const name = 'hello'; // does not affect output
callback();
callback.call({ name: 'world' }); // does not affect output
}
callFunction(jeff.sayName);
This has the advantages of:
Being easier to read,
Less code,
Allowing you explicit about the properties and methods being exposed through the object, and
Never having to worry about what the value of this will be.
I suppose you may want to achieve this
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function() {
console.log('my name' + this.name);
};
let jeff = new Human('jeff');
function callFunction(callback) {
callback();
}
callFunction(function() {
jeff.sayName()
});
another guess, a prototype bound to an instance, it works but has anti-patten
function Human(name) {
this.name = name;
}
const jeff = new Human('jeff');
Human.prototype.sayName = function() {
console.log('my name' + jeff.name);
};
function callFunction(callback) {
callback();
}
callFunction(jeff.sayName);
another guess, relection
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function() {
console.log('my name' + this.name);
};
Human.prototype.reflectName = function(item) {
this.sayName = () => item.sayName()
};
const jeff = new Human('jeff');
const tod = new Human('tod');
tod.reflectName(jeff)
tod.sayName()
Expanding on TinyGiant answer, you can use an arrow function, but if you combine it with a getter, you can define it as a method of the prototype and not bother with defining your callback as a arrow function, which may be more flexible depending on your needs. Like this:
function Human(name) {
this.name = name;
}
Object.defineProperty(Human.prototype, "sayName", {
get: function() {
return () => {
console.log("my name is", this.name);
}
}
});
function callfunction(callback) {
callback();
}
let jeff = new Human('jeff');
callfunction(jeff.sayName);
// just to show it works even as a regular function
jeff.sayName();
// in fact it overrides every context you bind
jeff.sayName.bind(window)()
Here's a sample of a simple Javascript class with a public and private method (fiddle: http://jsfiddle.net/gY4mh/).
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction();
}
}
ex = new Example;
ex.publicFunction();
Calling the private function from the public one results in "this" being the window object. How should I ensure my private methods are called with the class context and not window? Would this be undesirable?
Using closure. Basically any variable declared in function, remains available to functions inside that function :
var Example = (function() {
function Example() {
var self = this; // variable in function Example
function privateFunction() {
// The variable self is available to this function even after Example returns.
console.log(self);
}
self.publicFunction = function() {
privateFunction();
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Another approach is to use "apply" to explicitly set what the methods "this" should be bound to.
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.apply(foo, null);
// => foo
Yet another approach is to use "call":
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.call(foo, null);
// => foo
both "apply" and "call" take the object that you want to bind "this" to as the first argument and an array of arguments to pass in to the method you are calling as the second arg.
It is worth understanding how the value of this in javascript is determined in addition to just having someone tell you a code fix. In javascript, this is determined the following ways:
If you call a function via an object property as in object.method(), then this will be set to the object inside the method.
If you call a function directly without any object reference such as function(), then this will be set to either the global object (window in a browser) or in strict mode, it will be set to undefined.
If you create a new object with the new operator, then the constructor function for that object will be called with the value of this set to the newly created object instance. You can think of this as the same as item 1 above, the object is created and then the constructor method on it is called.
If you call a function with .call() or .apply() as in function.call(xxx), then you can determine exactly what this is set to by what argument you pass to .call() or .apply(). You can read more about .call() here and .apply() here on MDN.
If you use function.bind(xxx) this creates a small stub function that makes sure your function is called with the desired value of this. Internally, this likely just uses .apply(), but it's a shortcut for when you want a single callback function that will have the right value of this when it's called (when you aren't the direct caller of the function).
In a callback function, the caller of the callback function is responsible for determining the desired value of this. For example, in an event handler callback function, the browser generally sets this to be the DOM object that is handling the event.
There's a nice summary of these various methods here on MDN.
So, in your case, you are making a normal function call when you call privateFunction(). So, as expected the value of this is set as in option 2 above.
If you want to explictly set it to the current value of this in your method, then you can do so like this:
var Example = (function() {
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction.call(this);
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Other methods such as using a closure and defined var that = this are best used for the case of callback functions when you are not the caller of the function and thus can't use 1-4. There is no reason to do it that way in your particular case. I would say that using .call() is a better practice. Then, your function can actually use this and can behave like a private method which appears to be the behavior you seek.
I guess most used way to get this done is by simply caching (storing) the value of this in a local context variable
function Example() {
var that = this;
// ...
function privateFunction() {
console.log(that);
}
this.publicFunction = function() {
privateFunction();
}
}
a more convenient way is to invoke Function.prototype.bind to bind a context to a function (forever). However, the only restriction here is that this requires a ES5-ready browser and bound functions are slightly slower.
var privateFunction = function() {
console.log(this);
}.bind(this);
I would say the proper way is to use prototyping since it was after all how Javascript was designed. So:
var Example = function(){
this.prop = 'whatever';
}
Example.prototype.fn_1 = function(){
console.log(this.prop);
return this
}
Example.prototype.fn_2 = function(){
this.prop = 'not whatever';
return this
}
var e = new Example();
e.fn_1() //whatever
e.fn_2().fn_1() //not whatever
Here's a fiddle http://jsfiddle.net/BFm2V/
If you're not using EcmaScript5, I'd recommend using Underscore's (or LoDash's) bind function.
In addition to the other answers given here, if you don't have an ES5-ready browser, you can create your own "permanently-bound function" quite simply with code like so:
function boundFn(thisobj, fn) {
return function() {
fn.apply(thisobj, arguments);
};
}
Then use it like this:
var Example = (function() {
function Example() {
var privateFunction = boundFn(this, function() {
// "this" inside here is the same "this" that was passed to boundFn.
console.log(this);
});
this.publicFunction = function() {
privateFunction();
}
}
return Example;
}()); // I prefer this order of parentheses
Voilà -- this is magically the outer context's this instead of the inner one!
You can even get ES5-like functionality if it's missing in your browser like so (this does nothing if you already have it):
if (!Function.prototype.bind) {
Function.prototype.bind = function (thisobj) {
var that = this;
return function() {
that.apply(thisobj, arguments);
};
}:
}
Then use var yourFunction = function() {}.bind(thisobj); exactly the same way.
ES5-like code that is fully compliant (as possible), checking parameter types and so on, can be found at mozilla Function.prototype.bind. There are some differences that could trip you up if you're doing a few different advanced things with functions, so read up on it at the link if you want to go that route.
I would say assigning self to this is a common technique:
function Example() {
var self = this;
function privateFunction() {
console.log(self);
}
self.publicFunction = function() {
privateFunction();
};
}
Using apply (as others have suggested) also works, though it's a bit more complex in my opinion.
It might be beyond the scope of this question, but I would also recommend considering a different approach to JavaScript where you actually don't use the this keyword at all. A former colleague of mine at ThoughtWorks, Pete Hodgson, wrote a really helpful article, Class-less JavaScript, explaining one way to do this.
I have this Javascript constructor-
function TestEngine() {
this.id='Foo';
}
TestEngine.prototype.fooBar = function() {
this.id='bar';
return true;
}
TestEngine.prototype.start = function() {
this.fooBar();
}
TestEngine.prototype.startMethod = function() {
inter = setInterval(this.start, 200);
}
var test = new TestEngine();
test.startMethod();
Gives me this error -
Uncaught TypeError: Object [object global] has no method 'fooBar'
I tried console.log and found out that when I call this.start from within setInterval, this points to the window object. Why is this so?
The this pointer can point to one of many things depending upon the context:
In constructor functions (function calls preceded by new) this points to the newly created instance of the constructor.
When a function is called as a method of an object (e.g. obj.funct()) then the this pointer inside the function points to the object.
You can explicitly set what this points to by using call, apply or bind.
If none of the above then the this pointer points to the global object by default. In browsers this is the window object.
In your case you're calling this.start inside setInterval. Now consider this dummy implementation of setInterval:
function setInterval(funct, delay) {
// native code
}
It's important to understand that start is not being called as this.start. It's being called as funct. It's like doing something like this:
var funct = this.start;
funct();
Now both these functions would normally execute the same, but there's one tiny problem - the this pointer points to the global object in the second case while it points to the current this in the first.
An important distinction to make is that we're talking about the this pointer inside start. Consider:
this.start(); // this inside start points to this
var funct = this.start;
funct(); // this inside funct (start) point to window
This is not a bug. This is the way JavaScript works. When you call a function as a method of an object (see my second point above) the this pointer inside the function points to that object.
In the second case since funct is not being called as a method of an object the fourth rule is applied by default. Hence this points to window.
You can solve this problem by binding start to the current this pointer and then passing it to setInterval as follows:
setInterval(this.start.bind(this), 200);
That's it. Hope this explanation helped you understand a little bit more about the awesomeness of JavaScript.
Here is a neat way to do OOP with javascript:
//Global Namespace:
var MyNamespace = MyNamespace || {};
//Classes:
MyNamespace.MyObject = function () {
this.PublicVar = 'public'; //Public variable
var _privatVar = 'private'; //Private variable
//Public methods:
this.PublicMethod = function () {
}
//Private methods:
function PrivateMethod() {
}
}
//USAGE EXAMPLE:
var myObj = new MyNamespace.MyObject();
myObj.PublicMethod();
This way you encapsulate your methods and variables into a namespace/class to make it much easier use and maintain.
Therefore you could write your code like this:
var MyNamespace = MyNamespace || {};
//Class: TestEngine
MyNamespace.TestEngine = function () {
this.ID = null;
var _inter = null;
//Public methods:
this.StartMethod = function (id) {
this.ID = id;
_inter = setInterval(Start, 1000);
}
//Private methods:
function Start() {
FooBar();
console.log(this.ID);
}
function FooBar() {
this.ID = 'bar';
return true;
}
}
//USAGE EXAMPLE:
var testEngine = new MyNamespace.TestEngine();
testEngine.StartMethod('Foo');
console.log(testEngine.ID);
Initially, the ID is set to 'Foo'
After 1 second the ID is set to 'bar'
Notice all variables and methods are encapsulated inside the TestEngine class.
Try this:
function TestEngine() {
this.id='Foo';
}
TestEngine.prototype.fooBar = function() {
this.id='bar';
return true;
}
TestEngine.prototype.start = function() {
this.fooBar();
}
TestEngine.prototype.startMethod = function() {
var self = this;
var inter = setInterval(function() {
self.start();
}, 200);
}
var test = new TestEngine();
test.startMethod();
setInterval calls start function with window context. It means when start gets executed, this inside start function points to window object. And window object don't have any method called fooBar & you get the error.
Anonymous function approach:
It is a good practice to pass anonymous function to setInterval and call your function from it. This will be useful if your function makes use of this.
What I did is, created a temp variable self & assigned this to it when it is pointing your TestEngine instance & calling self.start() function with it.
Now inside start function, this will be pointing to your testInstance & everything will work as expected.
Bind approach:
Bind will make your life easier & also increase readability of your code.
TestEngine.prototype.startMethod = function() {
setInterval(this.start.bind(this), 200);
}
var name = 'The Window';
var object = {
name: 'My Object',
getNameFunc: function(){
return function() {
return this.name;
};
}
};
console.log( object.getNameFunc()() );
when i tested the code. the result is The Window. but i think this.name; should be My Object. what's wrong with my thinking.
when i add var before the name : "My Object", it show's an error.? why?
this inside a function is the "receiver" it was invoked upon.
That is,
for the construct x.f(), this inside the function (f) will evaluate to the value of x.
for all other cases, this will evaluate to window inside the invoked function. (The functions call, apply, and bind can also alter this... but that's another story.)
In the posted example the second function (the one with this.name) is not invoked using the x.f() form and so this is the window object.
The "simple fix" is to use a closure: (The first function is invoked in the x.f() form and thus this is the same as object, which is as expected. We capture the value of this in the current scope via a closure created with self and the returned function.)
getNameFunc : function () {
var self = this
return function () {
return self.name
}
}
However, I may consider another design, depending :)
Happy coding.
Additional clarification, for comment:
...that is because you are using circle.getArea() which is of the form x.f(). Thus this inside the getArea function evaluates to circle.
In the code posted you are invoking two different functions in a row. Imagine writing the code like this:
var nameFunc = object.getNameFunc()
nameFunc()
The first function call is in the form of x.f() and thus this inside getNameFunc is the evaluation of object. However, in the second line, the function (nameFunc) is not invoked in the form x.f(). Therefore, the this inside nameFunc (the function returned from getNameFunc) will evaluate to window, as discussed above.
var myObject = {
name:'My Object'
};
console.log(myObject.name);
console.log(myObject['name']);
There are various other ways to make objects in javascript.
this is a hidden argument that is automatically passed from the calling function to the callee. The traditional way is to do:
function MyObject() {
this.name = 'My Object';
}
myObject = new MyObject();
console.log(myObject.name);
Nowadays you might just use closures:
[**edit**: redacted because not a good method]
Nowadays you might just use closures, correctly:
function makeObject() {
var THIS = {};
THIS.name = 'My Object';
THIS.sayMyName = function () {
return THIS.name+" is my name";
}
return THIS;
}
There are many libraries that support "smarter" ways to make objects as well.
You need to use .bind() to set the right context for the method, so the this keyword will be what you want it to actually be.
The default is in such a scenario for the this keyword is to point to the window object, because...this is how the JS engine works.
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
}.bind(this); // <-- sets the context of "this" to "object"
}
};
console.log( object.getNameFunc()() );
As the others have written, you need to target this. I believe this piece of code will help you to understand how this in javascript works
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
that = this; // targeting this
return function() {
return that.name;
};
}
};
alert(object.getNameFunc()()); // it is My Object now
var object = {
name : "My Object",
getNameFunc : function(){
return (function(){
return this.name;
}).bind(this);
}
};
.bind, use the ES5-shim for browser support
The problem lies in the way you have declared your function.
The important point we need to remember while placing function inside a method is to use arrow function (if our function block is going to have a this keyword).
Instead of declaring a new variable and assigning this keyword to the variable, we can easily solve this problem using Arrow Functions.
Just convert the normal function into arrow function and boom it will work.
var name = 'The Window';
var object = {
name: 'My Object',
getNameFunc: function(){
return () => {
return this.name;
};
}
};
console.log( object.getNameFunc()() );
This works because arrow functions are always lexically binded and not dynamically binded like any other functions.