object issues of javascript - javascript

I constructed a function defined as
var Func1 = function()
{
return {
alert: function() { alert( "Lady Gaga" ); }
};
};
And I assigned Func1() to a variable, like this:
var func1 = Func1();
I found something make no sense to me that Func1() created an object for func1 although I didn't put the new in front of it.
Isn't that objects could only be created by new?
What happened when the expression above is being executed?

JavaScript doesn't need the new keyword. The above code assigned the return value to the newly created func1 variable.

When you write a javascript literal object (json like), it's the equivalent to create a new object with the new operator and assign its properties.
This
var a = { test: 123, caca: 'pipi' };
Is the same as
var a = new Object();
a.test = 123;
a.caca = 'pipi';

Look at what you are returning from Func1:
return {
alert: function() { alert( "Lady Gaga" ); }
};
You return an object, and that object is assigned to func1. So func1 = Func1(); simply calls Func1, and assigns the result of that to func1.

Your function is creating an object with:
{
alert: function() { alert( "Lady Gaga" ); }
};
Using that notation, there's no need to use the new operator.

The () actually executes the function, which returns an object with a method (a method is a property of type function).
In JS, you don't explicitly call new to create new objects:
var song = {
name: "Entrenched",
artist: "Morbid Angel"
};
song.artist = "Bolt Thrower";
This creates an object with the properties name and artist.

The new keyword used with a function is one way to create an object, but not the only way. It means that a new object will be created with the specified function called as a constructor - within the constructor the this keyword will reference the new object, and the new object will be returned. Call the same function without the new keyword and an object will not be created.
The object literal syntax (e.g., var x = { }; or return { };) is another way to create an object.

Related

Difference between different object notations

What is the difference between creating an object using an inline object constructor and creating an object by immediately invoking a contructor? I have always done the latter as it free's me from having to call something like init() myself and feels like the right thing to do, but I keep seeing the object notation in other people's code and was wondering if there is another difference I am not seeing.
Example:
window.fooModule = {
init: function() {
this.bar = "cee";
doStuff();
},
doStuff: function() {
...
}
}
window.fooModule.init();
Example2:
window.fooModule = new function(){
this.bar = "Cee";
this.doStuff = function() {
...
}
this.doStuff();
}
In first notation variable fooModel is object created without constructor call, in second notation fooModel is object created with call of constructor as anonymous function, so when using new keyword constructor function is called and object is created from its prototype ( in this example no prototype is declared so it is standard object prototype).
Conclusion
Use second notation if Your object has to call some code
when is created, use first if not.
More about second notation
Second notation enables also using local ( private ) variables and functions inside constructor, because constructor give us own scope.
var obj=new function(){
var priv="Local scope variable";
var method=function(){
console.log("Local method");
};
this.doStuff=function(){
//here local methods and variables can be used
};
};
Second notation with constructor and new is more often used with standard constructor function declaration and prototype declaration. This is correct way if We need to create more then one object. Methods and every shared properties should be declared in prototype not in constructor.
var ExampleClass=function(bar){
//constructor
this.bar = bar;
};
ExampleClass.prototype.doStuff=function(){
};
Creating such object:
var a=new ExampleClass("A bar"); //a.bar is "A bar"
var b=new ExampleClass("B bar"); //b.bar is "B bar"
Objects a and b have the same prototype ( it saves memory ) but they can have different properties set in constructor.
OffTop
In javascript is so many possibilities to create objects, I have third example how run code in first notation:
window.fooModule = {
init: function() {
this.bar = "cee";
this.doStuff();
return this;//return this
},
doStuff: function() {
}
}.init();//run init after object notation
I create object and run init in one time.
let the 1st example return obj1 and 2nd example return obj2
obj1 will have [[Prototype]] is an object. This object has constructor property is "function Object()"
obj2 will have [[Prototype]] is an object. This object has constructor property is anonymous function.
The way in 2nd example is usually used to achieve something we call "singleton"
Bonus: This stuff is easy to confused, but if you want to dig deeper, here is a good post for you
https://zeekat.nl/articles/constructors-considered-mildly-confusing.html
There are objects and there are object definitions prototypes. Neither of your examples are object definitions prototypes.
window.fooModule = function(bar){
this.bar = bar;
(this.doStuff = something => {
console.log(this.bar,'is doing', something || 'something');
})();
};
[a,b]= [new fooModule('a'), new fooModule('b')];
If you simply want to create an object, then you can skip the new and this operator.
(window.fooModule = {
bar : 'Cee',
doStuff : something => {
console.log(foo.bar,'is doing', something || 'something');
}}).doStuff();

Is it possible to call a method from an object definition constructor function

Say I have a constructor function in JavaScript, which I use to create my objects. How would I alter the "contents" of all the objects created by this function through a method call from this function. What I am wondering is, weather it is possible to invoke a method call upon the prototype, like we'd modify the prototype adding our own methods/properties.
For example:
function MyConstructor()
{
var privateVariable = "This is an ORIGINAL private variable";
this.publicVariable = "This is public";
this.modificationMethod = function(){
// I want to call this methode on the prototype
privateVariable = "I am now changed";
};
this.alertMe = function(){
alert(privateVariable);
};
}
var a = new MyConstructor();
a.alertMe(); // alerts This is an ORIGINAL private variable
a.modificationMethod();
a.alertMe(); // alerts I am now changed
This works when I want to change a single object, I invoke the method, it changes that single object. However, I want to change all the objects that are created by the constructor.
I know I can add new methods to it like this:
MyConstructor.prototype.foo = function(){
alert("foo");
}
a = new MyConstructor();
a.foo();
But it does not let me run the existing methods to change the properties, and throws an error:
MyConstructor.prototype.modificationMethod();
"modificationMethod is not a function"
EDIT: Updating the answer to reflect everything discussed in comments. I initially misunderstood the OP's issue.
Every object is linked to a prototype object. When trying to access a property that does not exist, JavaScript will look in the object's prototype object for that property and return it if it exists.
The prototype property of a function constructor refers to the prototype object of all instances created with that function when using new.
What that means is that prototype object is sort of a fallback mechanism when an object itself does not have the desired property.
The concept of private variables are in fact closures.
Prototype functions are defined outside of the constructor function scope, meaning they cannot access the "private properties".
However, it is possible to assign a closure to the prototype property itself, effectively making a private shared (static) variable.
function MyConstructor() {};
MyConstructor.prototype = (function() {
var extensions = {
foo: null,
test: function() {
alert("Test was extended");
}
};
return {
registerExtension: function(name, callback) {
extensions[name] = callback;
},
// in order to use the extensions object, you need a generic function such as invoke
invoke: function(name) {
if (typeof extensions[name] === 'function')
extensions[name].call(this);
}
};
}());
var a = new MyConstructor();
a.invoke('test'); //will alert
a.invoke('foo'); //will not alert (not a function)
a.registerExtension('foo', function() {
alert("foo is now extended as well");
});
a.invoke('test'); //will alert
a.invoke('foo'); //will alert
A simpler approach, if you don't mind for the extended functions to be visible (public), would be to directly extend the prototype.
function MyConstructor() {};
MyConstructor.prototype = {
foo: null,
test: function() {
alert("Test was extended");
}
};
var a = new MyConstructor();
a.test(); //will alert
//a.foo(); //will not alert (not a function)
MyConstructor.prototype.foo = function() {
alert("foo is now extended as well");
};
a = new MyConstructor();
a.test(); //will alert
a.foo(); //will alert
You can easily create an interface for prototype extension.
Object.prototype.registerExtension = function( name, func ){
this.prototype[ name ] = func;
};
// ...
MyConstructor.registerExtension( 'foo', function() {
alert("foo is now extended as well");
} );

Calling a function being "hidden" in another function

There is such a function from a third-party library:
(function($) {
window.NestedFormEvents = function() {
this.addFields = $.proxy(this.addFields, this);
this.removeFields = $.proxy(this.removeFields, this);
};
//......
NestedFormEvents.prototype = {
addFields: function(e) { .....
});
Is there any way to call addFields() from a client? typeof window.NestedFormEvents returns "function", but window.NestedFormEvents.addFields returns undefined as well as window.NestedFormEvents.addFields().
The source code is here: https://github.com/ryanb/nested_form/blob/master/vendor/assets/javascripts/jquery_nested_form.js
This is constructor function. When called with new keyword it returns new object which has methods defined in constructor's prototype:
var nestedFormEvent = new NestedFormEvents();
nestedFormEvent.addFields();
Now if you check console.log(nestedFormEvent) object you will see all necessary methods in it.
You're calling addFields as though it were a static method of NestedFormEvents.
Rather, it is a method of its prototype. So:
var instance = new NestedFormEvents;
alert(NestedFormEvents.addFields); //undefined
alert(instance.addFields); //finds function
In short, any time you're trying to use methods declared on a function's prototype, you need to instantiate it, with new.

prototype odd result when changing way to define

When trying to test prototype functionality, I got this odd result:
Here is my first test:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype.name = "Fred";
alert(a.name);
</script>
And, here's the second one:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype = {
name : "Fred",
}
alert(a.name);
</script>
I can't understand why the first will return a alert with "Fred" and the second is "undefined" though these mean the same thing?
Could you help me with it?
Thank you.
When you define a function in JavaScript, the interpreter makes a special prototype property available on the function, which points to an object, in case you use that function as a constructor. The [[Prototype]] internal property points to this object when you create a new object using the constructor.
When you replace the prototype property with a new one, you are replacing that reference, and if you do it after you instantiate an object, you will find the prototype object appears to be stale (that object's [[Prototype]] is pointing to the original object that prototype pointed to).
Solutions
Only assign new properties directly on the prototype property.
var constructor = function() { };
constructor.prototype.someMethod = function() { };
Use an extend type function to extend the existing prototype property with your new object (in this example, I used Underscore's extend() function).
var constructor = function() { };
_.extend(constructor.prototype, { someMethod: function() { } });
Make sure after the constructor, assigning the prototype property is the very next step in your program (generally not recommended).
var constructor = function() { };
constructor.prototype = { someMethod: function() { } };
Your ordering is messed up. You need assign the object to the prototype before using the new operator:
function Hello() {
}
Hello.prototype = {
name : "Fred",
}
var a = new Hello();
alert(a.name);​
Demo.
The two code snippets are not actually equal.
In the first script you only override Hello.prototype.name, while in the second script you override the whole content of Hello.prototype.

Invoking a function Object in JavaScript

I have a small question in JavaScript.
Here is a declaration:
function answerToLifeUniverseAndEverything() {
return 42;
}
var myLife = answerToLifeUniverseAndEverything();
If I do console.log(myLife), it will print 42, as I am just invoking the same instance of function resulting in 42 as the answer. (Basic rule on JavaScript that only references of objects are passed and not the object.)
Now, on the other, hand if I do:
var myLife = new answerToLifeUniverseAndEverything();
then I can't invoke the function; instead, myLife becomes just an object? I understand that this is a new copy of the same function object and not a reference, but why can't I invoke the method?
Can you please clarify the basic fundamental I am missing here?
By prefixing the call to answerToLifeUniverseAndEverything() with new you are telling JavaScript to invoke the function as a constructor function, similar (internally) to this:
var newInstance = {};
var obj = answerToLifeUniverseAndEverything.call(newInstance); // returs 42
if (typeof obj === 'object') {
return obj
} else {
return newInstance;
}
JavaScript proceeds to initialize the this variable inside the constructor function to point to a new instance of answerToLifeUniverseAndEverything. Unless you return a different Object yourself, this new instance will get returned, whether you like it or not.
When you do var myLife = answerToLifeUniverseAndEverything();, myLife is simply holding the return value from the function call - in this case, 42. myLife knows nothing about your function in that case, because the function was already called, returned, and then it assigned the resulting value (42) to the new variable myLife.
A completely different thing happens when you do var myLife = new answerToLifeUniverseAndEverything(); - instead, a new object is created, passed to the function as this, and then (assuming the function doesn't return an object itself), stored in the newly created variable. Since your function returns a number, not an object, the newly generated object is stored.
Try:
function answerToLifeUniverseAndEverything() {
return 42;
}
var myLife = answerToLifeUniverseAndEverything;
alert(myLife());
When you do:
var myLife = answerToLifeUniverseAndEverything();
you're assigning the function result to myLife ie 42.
I think i've described the behaviour of new elsewhere. Basically when you do new f() the JS engine creates an object and passes that as this, then uses that object if the return value of f() is not an object.
eg.
o = new f();
is equivalent (approximately) to
temp = {};
temp2 = f.call(temp);
o = typeof temp2 === "object" ? temp2 : temp;
If I do console.log(myLife) It'll print 42, as I am just invoking the same instance of function resulting in 42 as the answer. (Basic rule on javascripts that only references of objects are passed and not the object)
Not quite. This is because you're assigning the return value of answerToLifeUniverseAndEverything() to myLife. If you wanted to make a copy of the function, drop the brackets:
var myLife = answerToLifeUniverseAndEverything;
console.log(myLife());

Categories

Resources