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.
Related
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.
I tried to create this syntax for JavaScript:
var user = new Class({
name: 'No name',
sayHello: function () {
console.log(self.name);
}
});
user.sayHello(); // will print "undefined" because "self" isn't visible
And I created this implementation of Class:
function Class (_properties) {
var self = this;
// copy all properties and methods to this class
for (var _property_name in _properties) {
self[_property_name] = _properties[_property_name];
}
}
But the problem is in self that I wish to use in each class. The self.name will be undefined because self is a [Window object].
Question: how to modify my code to use self inside all functions in class instances? The self is needed to not drop context if the function will be called from external context.
Expected result (I mean that code above should be executed as code below):
function Class (_properties) {
var self = this;
// properties
self.name = 'No name';
// methods
self.sayHello = function sayHello () {
console.log(self.name);
};
}
var user = new Class();
user.sayHello();
The goal of my experiment is to use self that always is reference to current object. Because sometimes when we use calls like this $.get('...', function () { console.log(this); }) - this is set to function local scope. But I wish to use self (magic property) that always be a reference to object of current class (scope of current class).
So I finally figured out that you are talking about the self variable in the sayHello method that is giving you problems.
You need to google JavaScript scope this tutorial - it's not the most intuitive concept, but once you get it, everything will make sense.
In the mean time, it's worth pointing out that self is not a reserved word in JavaScript and doesn't do anything special, but this is.
So what you want, is something like this:
function Class (_properties) {
// copy all properties and methods to this class
for (var _property_name in _properties) {
this[_property_name] = _properties[_property_name];
}
}
var User = new Class({
name: 'No name',
sayHello: function () {
console.log(this.name);
}
});
var user1 = new User();
var user2 = new User();
The keyword new in front of the Class() function causes it to be executed as a constructor function meaning that, inside of the constructor function this will reference it's own scope.
Also, because the property sayHello is a function to be executed inside the scope that you created, you can use this.name - as this will refer to the scope that you created when you instantiated a new Class.
And just because this scope thing is no doubt confusing (don't worry, it probably will be for a while) - if you haven't created a scope (by using a constructor or object literal) you're working inside of the global scope which, in the case of the browser, is the Window object.
That's because you never created an object:
var options = {
name: 'No name',
sayHello: function () {
console.log(self.name);
}
}
var user1 = new Class(options);
var user2 = new Class(options);
"this" refers to the object owner of the current function. In this case would be windows object. At least you construct an object from the function Class.
If you want to avoid someone overwrite a property of Class.prototype is necessary to use hasOwnProperty in your for in
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
I'm learning javascript , so don't kill me.
I'm defining more different namespaces like this :
var name_Class = function(){
this.variable_name_1 = {}
this.method_name_1 = function() {}
}
and then..
var second_name_Class = function(){
this.variable_name_1 = {}
this.method_name_1 = function() {}
}
If i define and Initialiaze a variable in the first one and I try to call it in the second one , e.g. if a write c = new name_Class() it , e.g. redefine every array to [] so I cannot get the value I gave it before. Can you help me?
I'm not sure you understand what you're doing.
This
var name_Class = function(){
this.variable_name_1 = {}
this.method_name_1 = function() {}
}
defines a constructor function called name_Class (as an aside, constructors should have their first character capitalized by convention)
This
var c = new name_Class();
creates an object using that constructor. The new object is created and the constructor is bound to that object and called, setting the variable_name_1 and method_name_1 properties of the new object c. Each time you assign new name_Class() to a variable it will create a completely new object which has the constructor bound to it. Any changes you made to other objects created to the function will not have an effect on this new variable.
All of this is completely unrelated to your second Constructor, which you can use in the same way and is not affected at all by your first one.
Neither of these things are technically namespaces, they're classes or types. A namespace generally refers to a top level variable that other variables are defined as properties on. By default variables are defined on the global namespace, which for browsers is the window.
So to create your new object with type name_Class on a namespace namespace1 for instance, you could do
var namespace1 = {};
namespace1.c = new name_Class();
You can pass in arguments if you're looking to set values on an instance. eg
var Swatch = function(){
this.color = arguments[0] || 'green';
this.callback = arguments[1] || function() {
alert(this.color);
}
this.callback();
}
//defaults to green if no args are passed
var green = new Swatch();
//or pass in your own values
var red = new Swatch('red',function(){
alert('New swatch created with color '+this.color);
});
I have an instance function in javascript and for naming conventions I have other instance function added as property of the first instance function object. It's better illustrated in the following working JavaScript.
var MyModule = (function() { // instance function
return function() {
console.log("ran MyModule");
}
}());
MyModule.RelatedModule = (function() { //second instance function is a property of first instance function object
return function() {
console.log("ran RelatedModule");
}
}())
var inst1 = new MyModule(), // logs "ran MyModule"
inst2 = new MyModule.RelatedModule(); // logs "ran RelatedModule"
This works as intended with no errors. What I'd like to do though is to create the function definition for MyModule after I've created the MyModule object, can anyone help me achieve this? I've illustrated my attempts below.
var MyModule = {}; // create object first, try to set a constructor on it later
MyModule.RelatedModule = (function() { // add properties to the MyModule object
return function() {
console.log("ran RelatedModule");
}
}())
// the following does not work, I'd like to set the `MyModule` constructor instance function and retain the `MyModule.RelatedModule` property
MyModule.constructor = (function() {
return function() {
console.log("ran MyModule");
}
}());
So, how do I retain the properties of an object and change it's constructor?
You're confusing a couple of concepts. In your first example, MyModule doesn't have a constructor, it is a constructor. That is, it's a function object that you intend to use with the new operator to create new objects. Those objects will have a constructor property that points back to MyModule (the function that created them). Changing this constructor property won't have any effect on MyModule; that property is just a pointer back to the function that instantiated the object.
In other words, you can't change MyModule's constructor. That's a meaningless statement.
Now, when you write:
var MyModule = {};
...you create a new object whose constructor property is Object():
console.log(MyModule.constructor) // prints Object()
Again, changing this property doesn't really do much (except obfuscate some useful book-keeping).
At this point MyModule is just a plain-old object. It's not a function at all. That's why you're getting the "not a function" error. Because it's not, but you're trying to use it as though it is. If you want that name to refer to a function (i.e. to a different object) then you're going to lose all references to any properties you previously set, because you're pointing at an entirely new object.
That's just the way it is.
Now, you could save a reference to the object that contains all those previously-set properties and copy them back into MyObject once you've pointed that name at a function. But I'm not sure what the point would be.
Everything lwburk says is correct, however, the below does what you were trying to accomplish, it does this by calling an init() method from MyModule.
var MyModule = function(){
return this.init();
};
MyModule.prototype.init = function(){};
MyModule.RelatedModule = (function() { // add properties to the MyModule object
return function() {
console.log("ran RelatedModule");
};
}());
MyModule.prototype.init = function(){
console.log("ran MyModule");
};
var inst1 = new MyModule(),
inst2 = new MyModule.RelatedModule();
First, there is a known browser bug where the constructor property (of the constructed object) correctly resolves using the prototype, but is not applied in object construction. So you need the following polyfill:
function NEW(clas, ...args)
{
let res = Object.setPrototypeOf({}, clas.prototype);
res.constructor.apply(res, args);
return res;
}
Second, you need to be setting MyModule.prototype.constructor instead of MyModule.constructor. The reason is that MyModule.constructor is the function that constructs new classes, not the function that constructs new objects. (See: Why does a class have a "constructor" field in JavaScript?)
In other words:
var MyModule = {}; // create object first, try to set a constructor on it later
MyModule.RelatedModule = (function() { // add properties to the MyModule object
return function() {
console.log("ran RelatedModule");
}
}())
// set the `MyModule` prototype.constructor instance function and retain the `MyModule.RelatedModule` property
MyModule.prototype = {
constructor() {
console.log("ran MyModule");
}}
var inst1 = NEW(MyModule), // logs "ran MyModule"
inst2 = NEW(MyModule.RelatedModule); // logs "ran RelatedModule"
The short answer is that you can't do that. You can however change the prototype of an object. Check out this answer for insight into how to rethink your approach to work with this constraint: Changing constructor in JavaScript