Using _self so I always can have object context - javascript

What is the proper way to use _self to always have access to an object? Is using _self ok, or is it bad practice?
I want a good way to get at myObject's attributes and methods, even from functions that aren't called in myObject's context. There are solutions like .bind(this), using _self, and jQuery's $.proxy().
For example:
var myObject = {
name: 'Tyrion',
alias: 'imp',
_self: function() {
return this;
},
// I know this context is fine, but let's pretend it's being called from elsewhere.
getAlias: function() {
var _self = myObject._self();
return _self.alias;
}
}

In order to do what you're looking to do, you'd have to change a few things. #elclanrs is right about what your this context is. I'll put two options below.
var myObject = {
name: 'Tyrion',
alias: 'imp',
// I know this context is fine, but let's pretend it's being called from elsewhere.
getAlias: function() {
// you'd have to do this in every method.
var _self = this;
return _self.alias;
}
}
The other option is a bit different, and not as usable, but I'm adding it so you can see it:
var myObject = function() {
var _self = this;
_self.name = 'Tyrion';
_self.alias = 'imp';
_self.getAlias = function() {
return _self.alias;
};
};
in the second instance, getAlias would be better as a prototype method, but you won't have access to the _self variable, only this.

You can do this too but I wouldn't necessarily recommend it.
var obj = {
_self: this.obj, // if you don't have .obj it points to window
thing: 'thingy',
alsoThis: function() {
return 'another thing'
}
};
obj._self;
It's also possible that since it's not within a closure, or a function in otherwords, the context of this._self may be incorrect if the context is changed by the scope which its referenced in.
Generally, I just do var _self = this; right before a function which I am nesting another function within that requires the this context outside the parent function since the nested one will not have the ability to access the value of this being nested.
That's usually not too common in my experience, and you really shouldn't be declaring such a property/var that needs to be used for the purpose that _self vars serve. It isn't a good practice and would be best to not do.
What if you run into a situation where you need to have _self = some other context?

thisis determined by the invocation of the function. (aka, the way the function is called) See my other answers for more details.
var myObject = {
name: 'Tyrion',
alias: 'imp',
_self: function () {
return this;
},
// I know this context is fine, but let's pretend it's being called from elsewhere.
getAlias: function () {
var _self = myObject._self();
return _self.alias;
}
};
//member invocation
console.log(myObject._self() === myObject); // true
var aFucntion = myObject._self;
//functional invocation
console.log(aFucntion() === myObject); // false
console.log(aFucntion() === this); //true
Instead of worrying about the context of this, a workaround is to assign this to a value in an outer function, and then access that value in an inner functions. This is called closure
var MyObject = function (title) {
var _self = this,
helper = function () {
return _self.title + " " + _self.name;
};
this.title = title;
this.fullName = function () {
return helper(); //functional invocation
//if helper used this, this would be global
};
this.name = 'Tyrion';
this.alias = 'imp';
this.getAlias = function () {
//access to _self through closure
return _self.alias;
};
};
//constructor invocation
var aObject = new MyObject("Mr.");
console.log(aObject.getAlias()); //imp
console.log(aObject.fullName()); //Mr. Tyrion
FYI:
If _self returns myObject, context would not mater.
_self: function () {
return myObject;
}

Related

How to set var self = this; from outside the function?

I have a class-like function
var myapp = function() {
this.method = function() {
//Do something...
}
}
To reference myapp from within methods, the first line in the myapp function is
var self = this;
So a method in myapp can reference the "class" safely
this.anothermethod = function() {
self.method();
}
The full code:
var myapp = function() {
var self = this;
this.dosomething = function(Callback) {
Callback();
}
this.anothermethod = function() {
//Pass a callback ("self" is required here)...
this.dosomething(function() {
self.complete();
)};
}
this.complete = function() {
console.log('All done!');
}
}
My question is: can I assign var self = this; from outside the declaration of myapp? I don't want to set self every single time I write a "class".
Kind of like this:
var library = function() {
this.loadclass = function(Name) {
var tempclass = window[Name];
library[Name] = new tempclass();
library[Name].self = library[Name];
}
}
var myapp = new library();
myapp.loadclass('myapp');
myapp.myapp.dosomething();
It doesn't work as expected. self equals window for some reason.
I know it's a little abnormal programming, but can it be done?
Note about using self: I remember why I started using it. I wanted to reference the base class (this) from within callbacks inside methods. As soon as you try to use this within a function within a method, it then references the method, not the base class.
Unless you are detaching the methods from the object and calling them as plain functions, you don't need a self variable at all. The method can reach its object using the this keyword:
var myapp = function() {
this.method = function() {
//Do something...
}
this.anothermethod = function() {
this.method();
}
}
No, you can't really; not the way you're creating objects at least.
You can sort of do this, by enumerating all the functions on the object and binding them to the object itself. Something like this:
Object.keys(obj)
.filter(function(n) { return typeof obj[n] == "function" })
.forEach(function(n) { obj[n] = obj[n].bind(obj) })
This function will go over the public, enumerable properties of obj and make sure that any functions on it are bound to obj; i.e. this is now bound to obj.
A primer on this
When you call new, this within the constructor gets bound to the newly created object. If you do need a reference to this as it was bound at constructor time, you do need to keep away a reference to it.
Functions in JavaScript are bound to wherever it is called. Here's an example:
var foo = new function() {
this.bar = function() {
return 'bar'
}
this.baz = function() {
return this.bar()
}
}
console.log(foo.bar()) // bar
console.log(foo.baz()) // bar
var bar = function() {
return "window"
}
var baz = foo.baz
console.log(baz()) // window
When we call foo.baz() it'll look to foo for the implementation of bar, but when calling foo.baz through a "detached" reference, it'll look to whatever the global object is (in this case the browser window object) and call bar from there. Because we defined bar in the global context, it then returns window.
The practice of assign a variable called self is so that it doesn't matter how you call your methods, because you always reference the this at the time of creation through the self variable. You don't have to write things this way, but then you should understand that references to this may change under your feet.

this keyword is window object within a constructor function

Ok, so I thought I understood this (no pun intended), but apparently not.
var Constructor = function () {
var internalFunction = function () {
return this === window;
};
this.myMethod = function () {
alert(internalFunction());
};
};
var myObj = new Constructor();
myObj.myMethod();
This alerts true. Why can't the internal function see this as the object? Instead I have to use alert(internalFunction.call(this)); in myMethod.
Edit: I was looking for an explanation as to why this is assigned in that way, not workarounds such as var self = this;, etc. Sorry if I didn't make that clear.
this is not bound until the function is called and is dependent on how the function is called. You could think of it as an extra parameter implicitly passed to the function.
In this case, the problem is that you're calling internalFunction using internalFunction(). The this value is set either by calling a function as a method (as in foo.bar() or foo["bar"]()) or by setting this explictly via call() or apply(). Your call is doing neither so this reverts to the global object.
The simplest way to achieve what you want in this case while keeping internalFunction private is to store a reference to this inside the constructor function:
var Constructor = function() {
var thisObj = this;
var internalFunction = function () {
return thisObj === window;
};
thisObj.myMethod = function () {
alert(internalFunction());
};
}
Because of functional scoping rules, this is reassigned inside each function... I would store a copy of your object as self and use it accordingly...
var Constructor = function () {
var self = this;
var internalFunction = function () {
return self === window;
};
this.myMethod = function () {
alert(internalFunction());
};
};
var myObj = new Constructor();
myObj.myMethod();
Should give you the output you expect.
SIDENOTE
This is a fairly precarious practice that javascript has created, mainly because if you forget the new keyword when using Constructor, you will get this referring to the window (god) object so you'll be attaching myMethod to the window without warning.
There are five ways to call a function in JavaScript. The value of this depends on which you choose:
Global function call (e.g. myFunction()). No explicit value for this is given. The value of this will be the default object (window in a browser).
Method call (e.g. obj.myFunction()). The value of this is the object on which the method was invoked (obj in this case).
Using the call method (e.g. myFunction.call(obj)). The value of this is provided explicitly (in this case obj).
Using the apply method (e.g. myFunction.apply(obj)). The value of this is provided explicitly (in this case obj).
Constructor function (e.g. new MyFunction()). The value of this is a newly-created object provided by the runtime.
Each of the five is explained in more detail here:
http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx
Its a scope issue try something like:
var Constructor = function () {
var $this = this;
var internalFunction = function () {
return $this === window;
};
this.myMethod = function () {
alert(internalFunction());
};
};
var myObj = new Constructor();
myObj.myMethod();

how to get a reference to the defining 'class' inside an inner method in JavaScript?

I have the following JS code:
var Item = function ()
{
this.property = '';
this.myfunction = function ()
{
var value = this.property;
};
};
however, this does not point to the defining class so value doesn't get anything.
how do I access this.property from inside my function?
You need to create a closure which captures the value of parent scope's this:
var Item = function ()
{
this.property = '';
var self = this;
this.myfunction = function ()
{
var value = self.property;
};
};
Update: As others have pointed out, this closure is not needed when Item is used as a constructor (new Item()). Noting it here for future reference.
just create an alias for this. It will get closure'd.
var Item = function ()
{
this.property = '';
var self = this;
this.myfunction = function ()
{
var value = self.property;
};
};
Your code works as is if you call Item() as a constructor.
var item = new Item();
item.property = "the property";
item.myfunction(); // value = "the property"
this changes depending on the context. The context being how a function was invoked, not how it was defined, but how it was called.
Besides that, you seem to be mixing up two patterns here. I'm sure you meant something like:
var Item = function() {
this.property = '';
};
Item.prototype.myfunction = function() {
var value = this.property;
};
Instead you kind of mixed a closure pattern with prototypal, which doesn't seem very useful there. Closure is good for hiding members, allowing for true private members, but here you're exposing the property anyway. There's no reason not to stick that function on the prototype.
Do yourself a favor and ignore any concepts you have of more traditional OO, they won't do you any good here. Prototypal isn't nearly the same thing.

This pointer from internal function

i have JavaScript components, that has following architecture:
var MyComponent = function(params)
{
setup(params);
this.doSomething()
{
// doing something
};
function setup(params)
{
// Setup
// Interaction logic
var _this = this; // "this" points to DOMWindow, not to created object
$(".some-element").click(function(){
_this.doSomething(); // it craches here, because of above
});
}
};
When something, being controlled by interaction logic, happens, sometimes i must forward execution to "public" methods of component.
In this situation, i have a problem with "this" pointer.
Sample code demonstrates it:
var Item = function()
{
this.say = function()
{
alert("hello");
};
this.sayInternal = function()
{
_sayInternal();
};
function _sayInternal()
{
this.say();
};
};
To test it,
Create an object:
var o = new Item();
This works fine:
o.say(); // alerts "hello"
This crashes:
o.sayInternal();
I get an error:
TypeError: Result of expression 'this.say' [undefined] is not a function.
I think, such a behaviour takes place, because _sayInternal() function is declared (and not assigned to object, like "this.say = function()"). This way, it is shared across all created objects and acts like a static function in C++.
Is this true ?
No, sayInternal is not shared between created objects. But you are right, the created objects don't have access to sayInternal as it is not assigned to them. This function is only local to the constructor function.
this always refers to the context a function is invoked in. If you call it like func(), then this refers to the global object (which is window in browser). If you set the function as property of an object and call it with obj.func(), then this will refer to obj.
If you assign a "bound" function to a variable and call it:
var method = obj.func;
method();
then this will again refer to the global object. In JavaScript, functions are like any other value, they don't have a special relationship to the object they are assigned to.
You can explicitly set the context with call or apply:
var MyComponent = function(params)
{
setup.call(this, params); // <- using `call`
this.doSomething()
{
// doing something
};
function setup(params)
{
// Setup
// Interaction logic
var _this = this; // "this" to new created object
$(".some-element").click(function(){
_this.doSomething();
});
}
};
or in you other example:
var Item = function()
{
this.say = function()
{
alert("hello");
};
this.sayInternal = function()
{
_sayInternal.call(this);
};
function _sayInternal()
{
this.say();
};
};
That said, this approach to assign functions to objects is not good, because every instance will have its own this.sayInternal function. So for the Item code above, every creation of an instance involves creating three functions too, which is a waste of memory.
Making use of prototype inheritance would be a better way:
var Item = function() {
};
Item.prototype = (function() {
function _sayInternal() {
this.say();
};
return {
say: function() {
alert("hello");
},
sayInternal: function(){
_sayInternal.call(this);
}
}
}());
This way, _sayInternal is only created once and all instances inherit (refer to) the prototype, so say and sayInternal also exist only once. The "trick" with the immediate function makes _sayInternal only accessible by say and sayInternal.

Global instance in prototypal javascript

I am exploring a pattern where you can save a global reference to the current instance for simple use in anonymous functions where the this keyword is out of context. Consider this:
var instance;
var a = function(id) {
instance = this;
this.id = id;
};
a.prototype.get = function() {
return (function() {
return instance.id;
})();
};
var x = new a('x');
var y = new a('y');
console.log(x.get());
console.log(y.get());
This obviously won't work since instance is defined in the constructor, to each time .get() is called, instance will reference the last constructed object. So it yields 'y' both times.
However, I'm looking for a way to grab the instance inside a prototype method without using the this keyword, to make the code more readable. Singletons is not an option here, I need the prototypal inheritance.
Edit: Since you're avoiding to store "local instances", there are some approaches, for example:
Using call or apply to change the this value of the invoked function:
var a = function (id) {
this.id = id;
};
a.prototype.get = function () {
return (function() {
return this.id; // the inner `this` value will refer to the value of outside
}).call(this);
};
Using an argument:
//..
a.prototype.get = function () {
return (function(instance) {
return instance.id;
})(this);
};
The new ECMAScript 5th Edition introduced the bind method, which is extremely useful to persist the this value and optional bound arguments, you can find a compatible implementation here:
//..
a.prototype.get = function() {
var boundFunction = (function () {
return this.id;
}).bind(this);
return boundFunction(); // no matter how the function is invoked its `this`
}; // value will always refer to the instance.

Categories