Javascript Difference between normal function and function object - javascript

In Javascript, the way to create classes (or objects) is to use;
function MyObj()
{
this.someVar = "xyz";
this.someMethod = function(){}
}
My simple question is how different is this function from a normal JavaScript function...say a function which adds 2 numbers?

The function aren't different. What makes the difference is how you call them.
For example, those have the same effect :
function MyObj(){
this.someVar = "xyz";
this.someMethod = function(){
console.log(this.someVar);
}
}
var obj = new MyObj();
obj.someMethod();
and
function someMethod(){
console.log(this.someVar);
}
function MyObj(){
this.someVar = "xyz";
}
var obj = new MyObj();
someMethod.call(obj);
and
function someMethod(){
console.log(this.someVar);
}
function MyObj(){
this.someVar = "xyz";
}
var obj = new MyObj();
obj.f = someMethod;
obj.f();
As you tagged your question prototypal-inheritance, I'll complete by saying the best way to build your function would have been this one :
function MyObj(){
this.someVar = "xyz";
}
MyObj.prototype.someMethod = function(){
console.log(this.someVar);
}
var obj = new MyObj();
obj.someMethod();
This way, all instances of MyObj share the same function and thus are lighter.

The difference is not so much in the contents of the function, but in how you call it.
If you call var myObj = new MyObj() then a new object is created. By convention functions intended for use like this start with a capital letter.
If you were to call the function without the new keyword then exactly the same things happen inside the function, except that this will be the global object instead of the newly created object. This wouldn't matter in a simple "add 2 numbers" function, but can cause very odd bugs if you forget it.
One way to ensure that it doesn't matter if you forget the new call is to put this in the top of your function:
function MyObj() {
if (! (this instanceof MyObj)) {
return new MyObj();
}
...
}

None. What matters is the use of the new keyword.
See here:
function Fun(){
this.method = function(){
return "Bar";
}
return "Foo";
}
var value = Fun(); // assigns the return value of Fun() to value
alert(value); // "Foo"
// alert(value.method()); // won't work because "Foo".method doesn't exist
var instance = new Fun(); // assigns a new instance of Fun() to instance
alert(instance); // [object Object]
alert(instance.method()); // "Bar"

Related

Calling a method of an object's prototype

i'm new to JS and got the following problem:
Why is this not working / what is this code doing?
var Test = {};
Test.prop = "test property";
Test.Class1 = function () {
}
Test.Class1.prototype = {
m1: function() {
console.log(this.prop);
}
}
Test.Class1.m1();
My understanding of this code would be:
creating a new object called Test
adding the property prop to Test
creating a new object called Class1 in Test
adding a method m1 to Class1
calling the m1 method of Class1 in Test
In JavaScript, even the prototype property of a function is an object. Prior to creating an object whose prototype is the one you've defined, Test1.Class1.prototype is just a regular object. Basically it works the same way as the following code snippet:
var Test1 = { prototype { m1: function() {} } };
// You're trying to call an undefined function!
Test.m1();
// This is fine
Test1.prototype.m1();
In the other hand, when you use the new operator, you're creating a new object whose prototype is the one set to the constructor function. And here starts the magic:
var Test1 = function() {};
Test1.prototype = {
doStuff: function() {}
};
var object1 = new Test1();
// This works!
object1.doStuff();
When you access a property, JavaScript's runtimes inspect the object to find out if there's a function called doStuff, otherwise it looks for it on the object's prototype, otherwise it looks on the prototype of the prototype and so on...
Actually new operator is a syntactic sugar. ECMA-Script 5 introduced Object.create which makes everything more clear:
var Test1 = {
doStuff: function() {
}
};
// The first parameter of Object.create is
// the object that's going to be the prototype of
// Test1 object!
var object1 = Object.create(Test1);
// This works too!
object1.doStuff();
Probably you should check this other Q&A: How does JavaScript .prototype work?
You need to create an instance of the prototype before you're able to use its methods:
var instance = new Test.Class1();
console.log(instance.m1());
Even as such, Test.prop is not part of the instance, and will not be accessible to m1
Edit: Here's a working example:
var test = function() {
this.prop = "A property";
}
test.prototype.m1 = function() {
console.log(this.prop);
}
var instance = new test();
console.log(instance.m1());
prototype chaining only works for instances created with the new operator.
Otherwise you will have to explicitly call prototype to access the method.
let testClass = new Test.Class1();
testClass.m1();
Also since you are trying to access the prop property.
Test.Class1.prototype = {
m1: function() {
console.log(this.prop);
}
}
The call site is Test.Class1, the prop should be part of Test.Class1 and not on Test
I changed up the names of things, but this should work.
var Person = function(){
this.message = "Hello, world!";
};
Person.prototype = Object.create(Object.prototype);
Person.prototype.constructor = Person;
Person.prototype.greet = function(){
console.log(this.message);
alert(this.message);
};
var tom = new Person();
tom.greet();

access variable in object from another function

I am trying to access the variable myVar inside myObject from MyFunction, but get this error
Uncaught TypeError: Cannot read propperty 'myVar' of undefined
when running the code below.
var myObject;
function MyObject(){
this.myVar = 500;
MyFunction();
}
function MyFunction(){
alert(myObject.myVar);
}
myObject = new MyObject();
I have read this but still can't figure out how to access it.
When calling a function it's executed, and then the result is returned to the variable.
So, the function executes first, then the result is passed back to the variable
var myObject; // 1. new variable, undefined
function MyObject(){ // 3. execute function
this.myVar = 500; // 4. set a property
MyFunction(); // 5. call next function
}
function MyFunction(){
alert(myObject.myVar); // 6. myObject is still undefined,
} // result hasn't returned yet
myObject = new MyObject(); // 2. call function - 7. When everything is done
// executing, the result
// is returned
In other words, you can't do that.
One way to solve this would be to prototype the MyFunction and keep the value of this constant
function MyObject() {
this.myVar = 500;
this.MyFunction();
}
MyObject.prototype.MyFunction = function() {
alert(this.myVar);
}
var myObject = new MyObject();
FIDDLE
The problem is that myObject is assigned AFTER calling MyObject, so if inside it, myObject is still undefined.
Some alternatives:
function MyObject(){
this.myVar = 500;
myFunction.call(this); // Pass object as `this`
}
function myFunction(){
alert(this.myVar);
}
var myObject = new MyObject();
or
function MyObject(){
this.myVar = 500;
myFunction(this); // Pass object as argument
}
function myFunction(obj){
alert(obj.myVar);
}
var myObject = new MyObject();
or
var myObject;
function MyObject(){
this.myVar = 500;
}
function myFunction(obj){
alert(myObject.myVar);
}
var myObject = new MyObject(); // Now myObject is set
myFunction(); // Call `myFunction` after `MyObject`, not inside it.
or
var myObject;
function MyObject(){
this.myVar = 500;
this.myFunction(); // Prototype method
}
MyObject.prototype.myFunction = function(){
alert(this.myVar);
}
var myObject = new MyObject();
or
var myObject;
function MyObject(){
var that = this;
function myFunction(){ /* Place myFunction inside MyObject. Note that this
way each instance will have a copy of myFunction */
alert(that.myVar);
}
this.myVar = 500;
myFunction();
}
var myObject = new MyObject();
a good article you can find HERE
here is an example of defining a function like you wanted: FIDDLE
function MyObject() {
this.myVar = 500;
this.MyFunction();
}
MyObject.prototype.MyFunction = function() {
alert(this.myVar);
};
myObject = new MyObject();
(I think you know myObject and MyObject are different things (even unrelated to the interpreter, just their names are similar), but maybe that caused your confusion, so I'll just state this.)
What the interpreter will do is first evaluate the left-hand side of the assignment (new MyObject()) and then stuff it into the variable myObject. This means, that when you call function MyObject() { ... } the variable myObject has not yet been initialised`. Obviously (now), it is undefined, hence the error.
There are different ways to solve this, Omri Aharon's is one possibility.

How to access from 'private method' to 'public variable', in Javascript class

First, See my code plz.
function test(){
this.item = 'string';
this.exec = function(){
something();
}
function something(){
console.log(this.item);
console.log('string');
}
}
And I made class and call 'exec function', like this code
var t = new test();
t.exec();
But result is...
undefined
string
I wanna access from something function to test.item.
Have you any solution?
You need to call something with apply so that this is properly set inside of something:
function test(){
this.item = 'string';
this.exec = function(){
something.apply(this);
}
function something(){
console.log(this.item);
console.log('string');
}
}
As #aaronfay pointed out, this happens because this doesn't refer to the object that new test() created. You can read more about it here, but the general rule is:
If a function is invoked on an object, then this refers to that object. If a function is invoked on its own (as is the case in your code), then this refers to the global object, which in the browser is window.
You have many choices, but I recommend the last one.
var item = 'string'
or
this.exec = function(){
something.apply(this, []);
}
or
var that = this;
function something(){
console.log(that.item);
console.log('string');
}
this.item in something() isn't what you think it is.
The this value is different. In this case, it's the global object.
The best solution, in my opinion, is to declare a variable with a reference to this, that can be accessed inside the inner function.
function test() {
var that = this; // a reference to 'this'
function something() {
console.log(that.item); // using the outer 'this'
console.log('string');
}
this.item = 'string';
this.exec = function(){
something();
}
}
Why not just define something like this:
Fiddle
function test(){
this.item = 'string';
this.exec = function(){
this.something();
}
this.something = function(){
console.log(this.item);
console.log('string');
}
}
var t = new test();
t.exec();
// output:
// string
// string

Is it possible for a function called from within an object to have access to that object's scope?

I can't think of a way to explain what I'm after more than I've done in the title, so I'll repeat it. Is it possible for an anonymous function called from within an object to have access to that object's scope? The following code block should explain what I'm trying to do better than I can:
function myObj(testFunc) {
this.testFunc = testFunc;
this.Foo = function Foo(test) {
this.test = test;
this.saySomething = function(text) {
alert(text);
};
};
var Foo = this.Foo;
this.testFunc.apply(this);
}
var test = new myObj(function() {
var test = new Foo();
test.saySomething("Hello world");
});
When I run this, I get an error: "Foo is not defined." How do I ensure that Foo will be defined when I call the anonymous function? Here's a jsFiddle for further experimentation.
Edit: I am aware of the fact that adding the line var Foo = this.Foo; to the anonymous function I pass in to my instance of myObj will make this work. However, I'd like to avoid having to expose the variable inside the anonymous function--do I have any other options?.
Should be this.Foo:
var test = new myObj(function() {
var test = new this.Foo();
test.saySomething("Hello world");
});
http://jsfiddle.net/grzUd/5/
Or alternatively using with:
var test = new myObj(function() {
with (this) {
var test = new Foo();
test.saySomething("Hello world");
}
});
http://jsfiddle.net/grzUd/6/
Change var test = new Foo(); to var test = new this.Foo();.
Edit: Or you could pass it as a parameter.
function myObj(testFunc) {
this.testFunc = testFunc;
var Foo = function (test) {
this.test = test;
this.saySomething = function(text) {
alert(text);
};
};
this.testFunc(Foo);
}
var test = new myObj(function(Foo) {
var test = new Foo();
test.saySomething("Hello world");
});
You seem to be confused about the difference between identifier resolution on the scope chain and property resolution.
Foo is a property of an instance of myObj (i.e. it's an object property). Calling new Foo will resolve Foo as a variable on the scope chain, which isn't the right place to look for it. That's why Petah's answer tries to use with, to put the object properties of the this object on the scope chain.

Why won't this object's prototype's init function run

I use the following function for creating new objects.
function newObj(o) {
var params = Array.prototype.slice.call(arguments,1);
function F() {}
F.prototype = o;
var obj = new F();
if(params.length) {
obj.init.apply(obj,params);
}
return obj;
}
And it works well most of the time. However one of my base "classes" is now defined as inheriting from another base class
SPZ.EditablePuzzle = function () {
// function and variable definitions
return {
///some methods and properties
}
}();
SPZ.EditablePuzzle.prototype = SPZ.Puzzle;
Now when I use newObj() to create a new SPZ.EditablePuzzle the init function is not defined even though it is defined in SPZ.Puzzle and I make sure EditablePuzzle runs after Puzzle
Why won't my newObj function find the init function? Shouldn't it automatically look in the prototype as soon as it fails to find it in the object itself?
I suspect the inheritance is not well set. try doing
SPZ.EditablePuzzle.prototype = new SPZ.Puzzle;
Might solve this problem, though I am not sure.
Concerning the problem:
function Foo() {
}
Foo.prototype.init = function() {
console.log('bla');
};
function FooBar() {
}
FooBar.prototype = Foo; // looks fishy...
var kitten = new FooBar();
console.log(kitten.init); // yields undefined, uh what?
The problem is, that in this case Foo itself gets assigned to the prototype property, when in fact you wanted to do:
FooBar.prototype = Foo.prototype
See the difference? Foo has no init property as it is defined on the prototype object.

Categories

Resources