Keep this as context of base object in properties of javascript object - javascript

I am wondering what I need to do to maintain a type of (var self = this) coupling within sub properties of a java script object. For example, if I had the following object:
var t = {
helpers: {
getName: function(){
//how do i preserve this or get the mbase object instance here...
//so i can for example do the following:
var self = this;//this is now helpers object, but how to get to base object?
return self.nickName + "...";
},
getTime: function(){
}
},
nickName: 'test'
}
From what I understand currently, the this reference when in a object, is directly passed down into a function if it is a property of an object. Since this scenario is two objects don, is it the base or the "helpers" object when I reference (var self = this) and if so, how do I reach the base object property such as "nickNam" within obj.helpers.getNickName()?
Thanks in advance.

Related

how to access the properties of the parent object?

please help solve the problem.
i make 3 objects:
level:
var Level = function() {
self = this;
this.cellsObserver = new CellsObserver();
console.log('co from level ' + this.cellsObserver);
this.fieldObj = new Field();
}
field:
var Field = function() {
self = this;
this.init();
};
Field.prototype = Object.create(Level.prototype);
Field.prototype = {
init: function() {
console.log('co from field ' + self.cellsObserver);
}
}
observer:
var CellsObserver = function(){
.............
}
in result console output follow:
co from level [object Object] co from field undefined
I do not understand why in the second case output 'undefined'. because I have appointed a parent:
Field.prototype = Object.create(Level.prototype);
tl;dr: there is no field cellsObserver neither in Field or Level.prototype object. And there is no such thing as a classical 'self' in Javascript.
The long story.
When you're trying to fetch object.property, the Javascript will look at the object trying to find property, then to the object.prototype (which is another object) and so on until it get to the null prototype in the Object.prototype reference.
So, when you're calling second time the this.cellsObserver in Level constructor function, it goes like this:
this is a just new constructed object (if it called with the new keyword), and there is cellsObserver in the property list, so it'll be fetched without any deep lookup.
Then,
Field.prototype = Object.create(Level.prototype);
This only means that Field.prototype now will refer to a new object, which properties are the same as in Level.prototype in that moment.
From your code, there are no non-standard properties in Level.prototype object (you didn't provide any).
Then,
self = this;
Here you just assigning a global variable called self a reference to the just created object or window object (it depends). If you wish to store a reference to the this object, you should var: var self = this. But you should remember that this self variable could be accessed only in the scope where is was declared or in a closure.
Then,
Field.prototype = {
init: function() {
console.log('co from field ' + self.cellsObserver);
}
}
First of all, here you just override the previos instruction (Field.prototype = Object.create(Level.prototype);). If you want to extend the Field.prototype object, you could do in the Object.create call in second argument, or just by accessing a property like that: Field.prototype.init = function(){...}.
Second. The self variable could contain anything when the init function will be executed. Just use this for the current object here.
Third. Let's try to guess what will happen when this.cellsObserver get evaluated inside this init function.
The this object is referring to the Field instance, and there is no cellsObserver property there, so we move to the Field.prototype object, which is defined above ({ init: function () {...}}), there is no cellsObserver either, so we move to the Object.prototype object, which is null. Ok, our lookup is failed, this.cellsObserver is undefined.
What would be it look like if the Field.prototype = Object.create(Level.prototype) wasn't been overridden by the following code? The this object will refer to the Field instance as early. The Field.prototype is referring to the object which is copy of the Level.prototype object, and there is no cellsObserver here either. So, we look to the Object.prototype, and that's it. There is no cellsObserver in any objects except in the instances on Level class, which isn't referenced in any way in the Field instances.
You can play with that here: http://www.objectplayground.com/ by pasting this code:
var Level = function() {
this.cellsObserver = new CellsObserver();
this.fieldObj = new Field();
}
var Field = function() {
this.init();
};
Field.prototype = Object.create(Level.prototype);
Field.prototype.init = function() {};
this.field = new Field();
You are overriding the Field.prototype. Just assign to Field.prototype.init.

Binding Object Prototype Functions to Object in Javascript

Background
I have a prototype object that has dozens of functions that access info from a list like this:
var prototype_object = {
yellow: function(list) { return list[this.type+'_yellow']; },
green: function(list) { return list[this.type+'_green']; },
// ... 50 more functions here
}
The 'this.type' is supposed to come from the object that is assigned the prototype in a function:
function accessor(type) {
var widget = Object.create(prototype_object);
widget.type = type;
return widget;
}
I have a central list of information so now I can call:
var access_foo = accessor('foo'); // Create the accessor
access_foo.green(list); //Find 'foo_green' in the list
Problem
These accessor fxns are passed to different areas of the app and called after being assigned to new objects. Thus the 'this' in the prototype functions is being reassigned (as expected in javascript) and resulting in undefined types.
"SO BIND IT": We can bind to functions to set the 'this' which will create new functions. I can't afford to instantiate 60 new functions for 100s of dozens of object types in dozens of places.
"CALL IT": Call would require that I pass the original accessor as the 'this', but as I said, access_foo.green is passed somewhere else in the app and cannot reference back to access_foo on call.
"CHANGE THE PROTOTYPE_OBJECT PARAMS": Not an option the way the app is written.
In the end I need an object that knows its type and shares access to a large list of functions. Am I right in saying there's no way to create custom accessors that can be called out of context without having them all instantiate/bind to the full set of possible prototype functions?
You seem to have ruled out all the possible solutions. If you want a solution, you will have to adapt to use one of the options. If you're passing around accessor functions lots of places and you want them permanently bound to your object (so you don't have to also pass the object), then you will have to change how you're doing things.
The cleanest way would be to define the methods in the constructor and have the methods use a constructor local variable for the object reference and rely on the constructor closure instead of using this. Then, they would still work even though this was wrong. You will have to redo how you create your object in order to do that.
You could also redefine all your methods to pre-bind themselves. I will show code examples of both options.
Here's the closure method:
function myObj() {
var self = this;
self.prop1 = "foo";
// define all methods in here and use self instead of this
self.method1 = function() {
console.log(self.prop1);
}
}
var x = new myObj();
var m = x.method1;
m();
And, here's the pre-bind method while changing as little as possible of your existing code:
var prototype_object = {
yellow: function(list) { return list[this.type+'_yellow']; },
green: function(list) { return list[this.type+'_green']; },
// ... 50 more functions here
}
function accessor(type) {
var widget = Object.create(prototype_object);
widget.type = type;
// reassign prototype methods to the actual object and make them pre-bound
// to this particular instance
for (var method in prototype_object) {
if (typeof method === "function") {
// assign pre-bound method to the instance
widget[method] = widget[method].bind(widget);
}
}
return widget;
}
This one is a little more optimized version of the previous one that doesn't put the new methods on the prototype at all:
var prototype_object = {
yellow: function(list) { return list[this.type+'_yellow']; },
green: function(list) { return list[this.type+'_green']; },
// ... 50 more functions here
}
function accessor(type) {
var widget = {};
widget.type = type;
// reassign prototype methods to the actual object and make them pre-bound
// to this particular instance
for (var method in prototype_object) {
if (typeof method === "function" && prototype_object.hasOwnProperty(method)) {
// assign pre-bound method to the instance
widget[method] = prototype_object[method].bind(widget);
}
}
return widget;
}

Is it possible to get the name of the declaring scope of a variable?

I have a variable at some point of a JavaScript code. Now I would like to get the name of the function (aka scope) where that variable was declared. So for example if that variable is a field of an oject, I would like to get the name of the object's type.
Consider the following code:
function MyClass() {
this.name = "MyName";
this.age = 20;
}
var myVariable = new window.MyClass();
alert(getDeclaringScope(myVariable)) // should alert 'window'
alert(getDeclaringScope(myVariable.name)) // should alert 'MyClass
Is there any way to implement the getDeclaringScope function?
UPDATE
I wanted to use some technic like this to access to access a kind of "static" variable where meta information is stored for knockoutjs observable. A farly simplified example:
var META = {};
META["MyClass"] = {};
META["MyClass"]["MyArray"] = { ElementType: "MyOtherClass" };
function MyClass() {
this.MyArray = ko.observableArray();
}
function MyOtherClass() {
this.name = "a";
}
ko.observableArray.fn.addFromPlainObjects = function(plainItems) {
var elemType = .... here I wanted to get "MyOtherClass" from the META global variable
// create MyOtherClass and map the plain items to it... etc.
}
No.
The object has a reference to its constructor, but the constructor could be referenced from many objects, not just window in this case. It could be accessed directly with a variable (as opposed to a property):
var MyClass = window.MyClass;
var foo = new MyClass();
You can create a back-reference explicitly in your object model, as constructor functions are objects.
window.MyClass.backref = window;
Though this is most likely not what you want. I suspect you have a misunderstanding regarding what the scope of a variable is; a variable scope has nothing to do with object properties. As such, there is no notion of "declaring scope" that represents the object and object property from which a variable reference was retrieved, as you seem to conceptualize it.
You can use instanceof and constructor:
Eg.
myVariable instanceof MyClass; //true
myVariable.constructor;
// returns
function MyClass() {
this.name = "MyName";
this.age = 20;
}
Check: instanceof and constructor

Does a Javascript function return objects by reference or value by default?

I have an object defined outside the function, in a global scope. This object is not passed into the function as an argument, but the function does modify it and return the modified object.
What I wanted to know is, if the function returns a copy of the object, or the original global object?
Also, will passing that object to the function as an argument, make a difference, since objects are passed into functions by reference?
Whenever you're returning an object, you're returning a reference to the object. Likewise, when you're passing an object, you're passing a reference. However, passing an object in as an argument can be different than just changing an object in global scope, as these examples show. This is because the reference to the object is itself passed by value.
If you're changing the members of an object, then whether you pass it in as an argument or just update the global object makes no difference. Either way, you're working with the same object.
Example 1:
var object = {foo:'original'};
function changeObject() {
object.foo = 'changed';
return object;
}
console.log(changeObject()); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'changed'}
Example 2:
var object = {foo:'original'};
function changeArgument(object) {
object.foo = 'changed';
return object;
}
console.log(changeArgument(object)); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'changed'}
On the other hand, if you're overwriting the object with a new object, the change won't persist if you do it to the argument, but will persist if you do it to the global object. That's because the argument passes the reference to the object by value. Once you replace this value with a reference to a new object, you're not talking about the same object anymore.
Example 3:
var object = {foo:'original'};
function replaceObject() {
object = {foo:'changed'};
return object;
}
console.log(replaceObject()); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'changed'}
Example 4:
var object = {foo:'original'};
function replaceArgument(object) {
object = {foo:'changed'};
return object;
}
console.log(replaceArgument(object)); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'original'}
May be late comment, but this is typical challenge in any language.
Objects created on the heap and passed around by reference opposed to primitives(by value).
I think the root of the question is shared instance versus unique one to avoid unwelcome effects.
For example we calling a function to get a template(object) for new user to add to collection or want to clear the form
on cancel event from different modules to start over. It easy to understand and easy to overlook..test cases typically
not covering all usage permutations
The sanity checklist:
Here the shared instance:
var bigo = {
usr: { name: 'steven' },
bigi: function () {
return this.usr;
}
};
var outA = bigo.bigi();
var outB = bigo.bigi();
print(outA.name); // => steven
print(outB.name); // => steven
outA.name = 'ilan'; // change value
print(outA.name); // => ilan
print(outB.name); // => ilan
Non shared instance:
var bigo = {
bigi: function () {
var user = { name: 'steven' };
return user;
}
};
var outA = bigo.bigi();
var outB = bigo.bigi();
print(outA.name); // => steven
print(outB.name); // => steven
outA.name = 'ilan'; // change value
print(outA.name); // => ilan
print(outB.name); // => steven
What I wanted to know is, if the function returns a copy of the object, or the original global object?
Effectively, you only ever deal with references to objects in JavaScript. Even var foo = {} just assigns a reference to a new object to foo.
If the object is outside the function, you don't need to 'return' it. If you modify the object within the function it will update the object itself. Then you can reference the newly updated object in other functions as needed.
From your question this is how I think your code looks (more or less):
var o = {};
function f() {
o.prop = true;
return o;
}
In this case the global variable o references an object.
When you modify o you're modify whatever o references. Hence it modifies the original object.
When you return o you're returning a reference to the original object.
Passing the object to a function results in the reference to the original object being passed. Hence any modifications will affect the original object. For example:
var o = {};
f(o);
console.log(o.prop); // true
function f(o) {
o.prop = true;
}

Whats the difference declaring variables with and without prototypes

Whats the difference between (via prototypes)
var Todo = {};
Todo.prototype.name = "...";
Todo.prototype.hello = function() { ... }
Vs (variables & functions "outside" object)
var Todo = {}
Todo.name = "..."
Todo.hello = function() { ... }
Or even the below : variables & functions in object
var Todo = {
name: "...",
hello = function() { ... }
}
Think it like
A property or a function declared with prototype is an instance member of Todo.
A property or a function declared without prototype is a static member of Todo.
The first one doesn't make sense as you are dealing with an object instance (({}) instanceof Object === true), it won't have a prototype property (Object does).
You may be inquiring about the difference between these two patterns...
var ObjA = function() {
this.method = function() {};
};
var ObjB = function() {};
ObjB.prototype.method = function() {};
jsFiddle.
The former will use more memory when instantiated - each object has their own method. The latter won't each have their own method, the method lives on the prototype object, which is the next in command on the prototype chain when its attempted to be accessed on the parent.
Todo.prototype is also an object, so the difference is if you declare property with prototype, then every object who created from this prototype will have the property, otherwise, the property is only for Todo the object self.
A significant difference between method #1 and #2 (which is almost identical to example #3) is on new keyword that you need to use if you extend your function via prototype, e.g.
var Todo1 = function() {};
Todo1.prototype.name = "Foobar";
var Todo2 = {name: "Foobar" }
var a = Todo1;
console.log(a.name); // no property retrieved
var b = Todo2;
console.log(b.name); // Foobar
var c = new Todo1;
console.log(c.name); // Foobar

Categories

Resources