How to crossreference javascript class-properties? - javascript

In a project i experience problems with a javascript-scope. This is a basic question, but since im relatively new to js, it is hard to see the problem with this code.
The exception i got is: Uncaught TypeError: Cannot read property 'firstProperty' of undefined.
The jsfiddle
The code from the fiddle:
var someClass = function(){
var _someClass = {
firstProperty: 'hello world',
secondProperty: _someClass.firstProperty, // This line is not working like I expected it to work
}
return _someClass;
}
var someObject = new someClass();

If you want to reference firstProperty, then you can use something like this:
var someClass = function() {
var _someClass = new (function() {
this.firstProperty = 'hello world';
this.secondProperty = this.firstProperty;
})();
return _someClass;
}
var someObject = new someClass();
console.log(someObject.firstProperty);
console.log(someObject.secondProperty);
See it on JSFiddle.

This is because the _someClass.firstProperty is not yet defined. To make this work you should do something like this:
var someClass = function(){
var _someClass = {};
_someClass.firstProperty = 'hello world';
_someClass.secondProperty = _someClass.firstProperty;
return _someClass;
}
// The new here isn't actually necesary,
// since the object is created at the first
// line of the function. I actually don't
// know what happens here
var someObject = new someClass();
Also, to avoid future headaches, keep in mind that JS does not have classes. someClass is:
An object
A function
And since functions are objects and can have properties, you can use it as an object constructor but now I'm going off topic so I'll stop
This will help you look up more relevant information in the future

Related

Javascript Strategy Design Pattern issue

I am following this gist for a strategy design pattern.
https://gist.github.com/Integralist/5736427
I implemented this a few months ago and the chrome extension did not throw any errors when I implemented it but now its throwing a
"Uncaught TypeError: this.strategy is not a function"
var MessageHandling = function(strategy) {
this.strategy = strategy;
};
MessageHandling.prototype.greet = function() {
return this.strategy();
};
its strange because the functions that rely on this code still run but some other code that does not rely on it is limited.
Any ideas on how to fix it?
This is mainly about the object you create from MessageHandling, if you pass the right function while creating the object it should always work.
var MessageHandling = function(strategy) {
this.strategy = strategy;
};
MessageHandling.prototype.greet = function() {
return this.strategy();
};
var m = new MessageHandling(function(){console.log('hello');});
m.greet();
The above code will always work but if you instantiate the MessageHandling with passing a parameter which is not a function or not passing a parameter at all then it will complain that this.strategy is not a function. So you need to make sure you pass the right function to MessageHandling while creating its object.
You need to post your full code here in order for someone to figure out the problem. But from the exception text, it looks like you are passing an undefined strategy or a "variable that is not a function" to the constructor. The following sample will give the same "Uncaught TypeError: this.strategy is not a function exception:
// This is the Greeter constructor.
var Greeter = function(strategy) {
this.strategy = strategy;
};
// Greeter provides a greet function that is going to
// greet people using the Strategy passed to the constructor.
Greeter.prototype.greet = function() {
return this.strategy();
};
// Here are a couple of Strategies to use with our Greeter.
var politeGreetingStrategy = function() {
console.log("Hello.");
};
var friendlyGreetingStrategy = function() {
console.log("Hey!");
};
var boredGreetingStrategy = function() {
console.log("sup.");
};
var undefinedStrategy; //Not a function variable
// Let's use these strategies!
var politeGreeter = new Greeter(politeGreetingStrategy);
var friendlyGreeter = new Greeter(friendlyGreetingStrategy);
var boredGreeter = new Greeter(boredGreetingStrategy);
var wrongGreeter = new Greeter(undefinedStrategy); //No such strategy defined
politeGreeter.greet(); //=> Hello.
friendlyGreeter.greet(); //=> Hey!
boredGreeter.greet(); //=> sup.
wrongGreeter.greet(); //-> uncaught type

Issue when trying to inherit all classes referenced by name in a for loop

Well the title is a mouthful but I couldn't come up with a better one, ideas welcome.
Anyhow, I have a javascript object containing classes as properties. I want to create another object which is in every aspect equal to the first one by subclassing it. I'm gonna try to sum it up:
var L1 = {};
L1.Foo = function() {/*...*/};
L1.Bar = function() {/*...*/};
//...
L1.Baz = function() {/*...*/};
var L2 = {};
L2.Foo = function() { L1.Foo.call(this); /*possibily some other code here*/ };
L2.Foo.prototype = Object.create(L1.Foo.prototype);
L2.Foo.prototype.constructor = L2.Foo;
L2.Bar = function() { L1.Bar.call(this); /*possibily some other code here*/ };
L2.Bar.prototype = Object.create(L1.Bar.prototype);
L2.Bar.prototype.constructor = L2.Bar;
//...
L2.Baz = function() { L1.Baz.call(this); /*possibily some other code here*/ };
L2.Baz.prototype = Object.create(L1.Baz.prototype);
L2.Baz.prototype.constructor = L2.Baz;
var foo = new L2.Foo();
console.log(foo); //L2.Foo
var bar = new L2.Bar();
console.log(bar); //L2.Bar
var baz = new L2.Baz();
console.log(baz); //L2.Baz
First, working version.
I told myself: "huh, looks like there a pattern here" so I went and modified my code as follows:
//first 10 lines unaltered
for(prop in L1) {
L2[prop] = function() { L1[prop].call(this); /*Call super method by default,
unless overriden below*/ };
L2[prop].prototype = Object.create(L1[prop].prototype);
L2[prop].prototype.constructor = L2[prop];
}
//Here I decide that I want to override only the constructor
//for Foo, so naturally:
L2.Foo.prototype.constructor = function() {
L1.Foo.call(this);
this.someOtherProperty = "foo";
};
var foo = new L2.Foo();
console.log(foo); //L2.(anonymous function)?
console.log(foo.someOtherProperty); //undefined?
var bar = new L2.Bar();
console.log(bar); //L2.(anonymous function)?
var baz = new L2.Baz();
console.log(baz); //L2.(anonymous function)?
Second, not-so-working version.
What I am getting wrong?
"huh, looks like there a pattern here" so I went and modified my code
as follows:
for(prop in L1) {
L2[prop] = function() { L1[prop].call(this);
You've hit the common closure in a loop problem - all your L2 functions are actually calling L1.Baz on their new instance as prop will have the value "Baz". See the linked question for how to fix this.
Also, notice that none of your constructors does pass its arguments to the super call, which might bite you as well.
Here I decide that I want to override only the constructor for Foo, so
naturally:
L2.Foo.prototype.constructor = function() {
L1.Foo.call(this);
this.someOtherProperty = "foo";
};
What I am getting wrong?
Overwriting the .constructor property on a prototype object does nothing. Your code is still invoking new L2.Foo, not new L2.Foo.prototype.constructor. You might want to have a look at how the new keyword works.
Instead, you really need to replace L2.Foo. This can be done with this pattern:
L2.Foo = (function (original) {
function Foo() {
original.apply(this, arguments); // apply old L2.Foo constructor
this.someOtherProperty = "foo"; // set property
}
Foo.prototype = original.prototype; // reset prototype
Foo.prototype.constructor = Foo; // fix constructor property
return Foo;
})(L2.Foo);
(or you just put your standard pattern from the first version). If this does get too repetitive, you might also do the .prototype and .constructor setup programmatically:
// whole code
var L2 = {
Foo: function() {
L1.Foo.call(this);
this.someOtherProperty = "foo";
}
// … other overwritten constructors
};
for (var prop in L1) {
if (!L2[prop]) // unless overridden above, create default that only…
(function(parent) {
L2[prop] = function() {
parent.apply(this, arguments); // calls super
};
}(L1[prop]));
L2[prop].prototype = Object.create(L1[prop].prototype);
L2[prop].prototype.constructor = L2[prop];
}
This might just be me, but if the subclass needs to be the same in every aspect as the superclass, why bother making a subclass? I'm not entirely clear an what you are trying to achieve from the code.
But just give the class a property of the class itself
e.g. (in plain java)
public class TestInheritClass {
private TestInheritClass tic;
public TestInheritClass getTic() {
return tic;
}
public void setTic(TestInheritClass tic) {
this.tic = tic;
}
}

Adding a property to a "Class" in JavaScript

There are no actual classes in javascript. But you have to work with what you get.
Lets take this example "Class":
var example = function (string) {
this._self = string;
}
With the above, you could do something like:
var ex = new example("Hello People."),
display = ex._self; // returns "Hello People."
I thought that by using something like example.prototype.newFun = function(){} would add a new property to that "Class". But it isn't working in my code.
Here is the full code i'm testing:
var example = function (string) {
this._self = string;//public, var like, storage
}
var showExample = new example("Hello People");
showExample.prototype.display = function (a) {//code stops here, with error "Uncaught TypeError: Cannot set property 'display' of undefined"
return a;
}
console.log(showExample._self);
console.log(showExample.display("Bye"));
What i'm trying to do is add the display function to the example function as a "public function". I might be doing something wrong.
It's not the object that has the prototype, it's the function that you use to create the object:
var example = function (string) {
this._self = string;
}
example.prototype.display = function (a) {
return a;
};
Because there's no prototype for showExample - it's only an instance of example. Try to do this: example.prototype.display = function (a) {} and it will work.
Here's a bit more on classes in JavaScript:
3 Ways to "define" classes
This lovely SO question
I like the way Classy handles this and also how classes are implemented in CoffeeScript.
You can modify to the constructor of showExample ..
ex.
showExample.constructor.prototype.display = function (a) {
return a;
}
You try to add a method to the prototype of the instance of example (showExample). The instance has no prototype. Try example.prototype.display = function() {/*...*/}; (in other words, add the method to the prototype of the constructor of showExample, that is example) and check again. After that, all instances of example 'know' the display method, or in your words, display is 'public' to all instances.
You can add the method to the instance using showExample.display = function() {/*...*/};. Using that, only showExample knows the the display method.
in your case showExample is an object of example...
use
example.prototype.display = function(a)...

Overhead of declaring prototype of object on each instantiation?

So there has been much discussion on the topic of accessing private members inside of prototype methods. The thought occurred to me that the following should work:
function Test(){
var private = "Private";
this.instance = function(){
return private;
};
Test.prototype.getPrivate = function(){
return private;
};
}
var test1 = new Test();
var test2 = new Test();
console.log(test1.instance === test2.instance); // false
console.log(test1.getPrivate === test2.getPrivate); // true
Turns out it does, in fact, work. I'm concerned, however, that there might be a drawback to doing this.
So my question is: Is there a drawback?
This doesn't work the way you probably expect, as test1's getPrivate() gets test2's private.
function Test(value){
var private = value;
this.instance = function(){ return private; };
Test.prototype.getPrivate = function(){
return private;
};
}
var test1 = new Test("test1");
var test2 = new Test("test2");
console.log(test1.getPrivate()); // test2
console.log(test2.getPrivate()); // test2
so it really doesn't matter if it is inefficient as it doesn't work.
I believe you did make a mistake in defining the prototype function inside of the function itself. This way everytime an instance is generated the prototype method available to all instances is overwritten ... that's the strange thing you're seeing I guess.
function Test(param){
var private = param;
this._getPrivate = function(){
return private;
};
}
Test.prototype.getPrivate = function(){
return this.instance();
};
var test1 = new Test("One");
var test2 = new Test(2);
console.log(test1.getPrivate());
console.log(test2.getPrivate());
This one works as expected.
But then, I don't understand what you need the prototype function for ... if you just defined the closure as a member-function, like you do (adding it to this instead of making it local), you get the same syntax as with using prototype. Hmmm, don't quite get what you intended - could it be you were just playing around with prototype?? gg
But then, if you're interested in accessing properties have a look at this code (EcmaScript 5 defineProperty) I took out of the - methinks - amazing prototypal tool (that comes without Prototypes drawbacks) Sugar ... (they actually use it to enable Events on PropertyChange! How very cool, anyway, doesn't work in legacy browsers <-> ES 5!)
Object.defineProperty(myObj, MyProp, {
'enumerable' : true,
'configurable': true,
'get': function() {
return value;
},
'set': function(to) {
value = calculateSomething(to);
}
});

How dangerous is modifying a function directly?

To get around what has proven to be a scope limitation to me (as answered here), I've written a piece of code which inserts a line in an anonymous function so that whoever writes the function doesn't have to do it themselves. It's a bit hacky (actually, it feels quite a lot hacky), and I really don't know what I'm doing, so I'd appreciate an expert eye to catch any errors I may have missed or point out any dangers I'm unaware of. Here's the code:
function myObj(testFunc) {
this.testFunc = testFunc;
this.Foo = function Foo(test) {
this.test = test;
this.saySomething = function(text) {
alert(text);
};
};
var Foo = this.Foo;
var funcSep = this.testFunc.toString().split("{");
funcSep.splice(0, 1);
funcSep = funcSep.join("{");
var compFunc = " var Foo = this.Foo;" + funcSep;
compFunc = compFunc.split("}");
compFunc.splice(compFunc.length - 1, 1);
compFunc.join("}");
var otherTestFunc = new Function(compFunc);
otherTestFunc.apply(this);
}
var test = new myObj(function() {
var test = new Foo();
test.saySomething("Hello world");
});
The function above evaluates as expected, and I don't need to force whoever writes the anonymous function to obtain access to Foo by using this.Foo. This approach feels iffy, though. Is what I'm doing acceptable, and if not, are there any ways to circumvent it?
Also, the only reason I didn't include this in my original question is that seems like something of a departure from the original context of the question.
You're trying to break the language. Don't do that. It's not Java.
Developers have certain expectations on the behaviour and scope of variables, and your approach would rather confuse them. Think about the following:
var Foo = SomeWonderfulClass;
var test = new myObj(function() {
var test = new Foo();
// ...
});
Now the developer wants to instantiate SomeWonderfulClass, but your magic messes around with that.
On the other hand, this would work fine, even with your trickery:
var test = new myObj(function() {
var Foo = SomeWonderfulClass;
var test = new Foo();
// ...
});
But the bigger problem is that the actual scope is lost:
var Bananas = SomeWonderfulClass;
var test = new myObj(function() {
var test = new Bananas(); // Error: Bananas is undefined!
});
Nobody expects such shenanigans.
That being said, there's some things about your code to be improved:
this.Foo is initialized with every new object. That's not necessary. Better use
myObj.prototype.Foo = function () {...}
The line var Foo = this.Foo; is not needed in myObj.
Your string magic is overly complex. How about
var otherTestFunc = new Function(testFunc.toString()
.replace(/^[^{]+{/, '{var Foo=this.Foo;'));
No need to remove the braces.
(testFunc does not accept any arguments, but I guess you know that.)
So that boils down to
function myObj(testFunc) {
this.testFunc = testFunc;
var otherTestFunc = new Function(testFunc.toString()
.replace(/^[^{]+{/, '{var Foo=this.Foo;'));
otherTestFunc.apply(this);
}
myObj.prototype.Foo = function Foo(test) {
this.test = test;
this.saySomething = function(text) {
alert(text);
};
};
I've been bothered by this method since I saw it in asp.net validation code (!). Not really safe for arbitrary function:
var f = (function () {
var closure = 1
return function (argument) {
alert(argument)
alert(closure)
}
})()
var f2 = new Function(f.toString().replace(/^function.*?{([\s\S]*)}$/, 'alert(1);$1'))
f2(1) // :(
Arguments could be saved though.

Categories

Resources