difference between these functions - javascript

What is the difference between these 3 functions? What use is the new operator in the second function? Why should one use the first function over the third function?
First
var person = function(name){
this.name = alert(name);
};
var k = new person('kkkk');
var j = new person('jjjj');
Second
var person2 = function(name){
person2.name = alert(name);
};
var k2 = new person2('kkkk2');
var j2 = new person2('jjjj2');
Third
var person3 = function(name){
person3.name = alert(name);
};
var k3 = person3('kkkk3');
var j3 = person3('jjjj3');

The alert actually makes it pretty hard to examine the effects, so in my explanations, I'll assume alert(name) is actually name. (alert returns undefined, not its input)
The first one makes a function that you could use like a class. You then used it with new and made two objects, k and j. The this made it so you could access the names such that k.name === 'kkkk' and j.name === 'jjjj'.
The second one is similar to the first one, but k2.name and j2.name are undefined. You can access person2.name, but that's only equal to the name of the last time you instantiated it; thus, person2.name === 'jjjj2'.
The third one is similar to the second one, but doesn't abuse new. k3 and j3 are undefined, and you will get an error if you try to access k3.name and j3.name. Again, you will be able to access the value last passed to person3 with person3.name.

Your second and third function will not assign anything to person2.name and person3.name. So technically only your first function is valid that's why it should be used.
There is a very important concept in javascript called context. A context can be thought of as an object. this keyword refers to the context in which a function is executing.
You can create a new property in current context with the help of this. For example:
var person = function(name) {
this.name = name; // this can be accessed externally, just like public properties
var _name = name; // this can be accessed only within the function, just like a private property
__name = name; // if a property is not properly initialized with a 'var' or 'this', it becomes part of 'window' object, hence you can access it from anywhere using 'window.__name'
}
You can create a new context using new keyword:
var k = new person2('kkkk2'); // this will create a new context, create a property name in it and assign it value passed to function.
var j = new person('jjjj'); // this will create another context
You can always access different contexts and their properties:
alert(k.name); // this will show 'kkkk2'
alert(j.name); // this will show 'jjjj'

The first one declares a function, person(), that is (presumably) intended to be used as an object constructor - kind of the closest JavaScript comes to having classes. That means if you call it with new person() JS will create a new instance of a person object, and within the constructor this refers to that new instance so this.name creates a property on the instance. Unfortunately the value you've assigned to that property is undefined since the alert() function returns undefined. If you said this.name = name it would store the value that was in the function argument - that would be a more normal usage. Your k and j objects both have a name property with this syntax.
The second version, again with the new person2() syntax, will be creating objects that are instances of person2, however saying person2.name creates a property on the function itself. So that property is not accessible directly from the instances k2 and j2, and every time you call person2() the person2.name property gets overwritten. There is no problem with having properties on functions like this in a general sense, but in this case it doesn't really make sense unless you really need to remember the name associated with the most recent invocation.
The third version, without using the new keyword, will simply assign the return value from person3() to the k3 and j3 variables, but since you don't explicitly return anything they'll end up as undefined. And the person3.name will work exactly the same way as for person2.
EDIT: Except, note that name has special meaning in the context of functions, so for the second and third options it won't behave quite the same as if you created a property with some other name that doesn't have special meaning, e.g., myName.

Related

Difference between normal object variable and prototype variable javascript

In javascript whats the difference when i create a variable in object like below 2 ways
user.name = 'hello';
user.prototype.name = 'hello';
Fundamentally, there isn't any, in that in both cases you're creating or modifying a property on an object. But the effect of creating/modifying that property can be significant.
First, note that user will only have a property called prototype if it's a function* (or if you've created one on another kind of object). I'm going to assume that user is a function for the remainder of this answer. And since we're using user as a constructor, I'll use User instead for the rest of this answer as the overwhelming convention in JavaScript is that the names of constructor functions start with an uppercase character.
User.prototype is used if you create objects via new User. In that case, the object that User.prototype refers to will be used as the new object's prototype. That means that if you try to retrieve the value of a property on that new object and the object doesn't have a property with the given name, the JavaScript engine will look at the object's prototype to try to find it.
So adding or modifying a property on User.prototype may seem to add it to objects you've created via new User:
function User() {
}
var u1 = new User();
console.log(u1.name); // undefined
User.prototype.name = "hello";
console.log(u1.name); // "hello"
It hasn't actually been added to u1, it's just that since u1 doesn't have its own name property, when we look up name on it, the property from its prototype is used instead.
To further understand the relationship between a function's prototype property and the prototype of an object, see __proto__ VS. prototype in JavaScript.
* It needs to be a function created via the function or class keyword to have a prototype property by default; arrow functions, async functions, and methods don't have prototype by default and cannot be used as constructor functions.
First scenario:
user.name = 'hello'
if you have created an object like this:
var user = { id:'abc'};
and then you do user.name = 'hello', will simply add a property to the user object as
user{name:'hello',id:'abc'}
Second scenario:
user.prototype.name = 'hello';
if you have created an object using constructor;
eg;
function User(id) {
this.id = id;// creating an object which will differ in id;
}
now:
user.prototype.name ='hello';
will initialize any instance of user with the name as hello. We use prototype when we want the instances to have the same property and has only one copy in case of methods.
eg
var newUser = new user('id');
now newUser will be -
newUser{id:'id',name:'hello'}

un expexted behaviour of javascript constructor when called without new keyword

I created a class using function like -
function Person(name) {
this.name = name;
}
var obj = new Person("Ferdinand");
console.log(obj.name);
I am creating an object obj and prints its property name it is working fine and prints "Ferdinand", but if we forget to write new key word like below program -
function Person(name) {
this.name = name;
}
var obj = Person("Ferdinand");
console.log(name);
Here I am not able to understand why name is available in console, it is printing "Ferdinand". But we are using Person as a function and assigning name variable in function itself so why its value is available outside function.
JavaScript does not implement objects in the classical sense. Instead, they are implemented directly:
var thing={}; // new object
Because you typically want multiple objects to follow a common pattern and behaviour, you can use what is called a constructor function to help. In your example, Person is a constructor function.
When using a constructor, you call it indirectly using the new command:
var thing = new Person(…);
In fact, there’s a lot of magic going on here:
JavaScript begins by creating a new object: var thing={};.
Then the this key word is assigned to the new object
Finally the constructor is run, using the this value to assign local values.
If you call a constructor function directly, the first 2 steps do not apply, and the function is left trying to work in its own definition of this which is generally not what you want.
If you really want to call the constructor function without bothering with new, you can try the following:
function Person(data) {
// “new” safe constructor
if(!(this instanceof Person)) {
return new Person(data);
}
This new version checks whether it is being called as a proper constructor, and, if not, calls itself properly.

If a variable is enclosed, and an instance sets a property with the same name, where does the property go?

Most of us know that JavaScript has no sense of "private" properties, but that behavior can be emulated through the use of closures:
var Car = function () {
var name = 'Tesla';
var wheelCount = 4;
this.getName = function () {
return name;
};
this.getWheelCount = function () {
return wheelCount;
};
this.setName = function (newName) {
name = newName;
};
this.setWheelCount = function (newCount) {
wheelCount = newCount;
};
};
var myCar = new Car();
console.log(myCar.name); // undefined
That all makes sense to us that know about how JavaScript closures work. However, the following will work:
myCar.name = 'Corvette';
console.log(myCar.name); // 'Corvette'
But then if you call the function from the prototype, the enclosed variable is still used
console.log(myCar.getName()); // 'Tesla'
When you call myCar.name, you're adding a new property to the object. Is it just the entire point of using this when declaring the getName (etc) functions inside the Car definition to make the differentiation between the enclosed name inside the Car declaration versus the myCar.name?
I have a feeling that I know the answer to this, but I would like to be certain. Plus, I think this would be something invaluable to other people getting an advanced grasp on how JavaScript enclosures work.
Is it just the entire point of using this when declaring the getName (etc) functions inside the Car definition to make the differentiation between the enclosed name inside the Car declaration versus the myCar.name?
Yes.
this (or myCar) is the object, on which you put the properties that you want to have it (in this case all those methods). If you want to use properties, you must use a property accessor.
var name is just a local variable in the constructor function, which is accessed by closure from the object's methods.
Or, to answer your title question:
If a variable is enclosed, and an instance sets a property with the same name, where does the property go?
The property goes on the object. It doesn't interfere at all with the variable, which is located in the scope of the Car constructor invocation.
In your example car function is a constructor function. When a constructor function is called with new operator, a new object is created and "this" gets bound to that new object. And "this" is returned from the function even if there is no return statement (unlike non-constructor functions that returns undefined if nothing is returned)
So When you called new Car() a new object got created and as "this" was bounded to this new object, the new object got 4 functions that you defined in Car function (getName, getWheelCount, setName, setWheelCount)
The name variable defined in Car function is not bounded to "this", it is bounded to Car's function scope. When car function returned "this", because of closure getName() still has access to function's name variable.
Now when you tried myCar.name, as the new object that was created does not have any variable called name, it printed undefined.
On doing myCar.name = 'Corvette', as no property named name was found in myCar,new property was created with name "name" and value "Corvette" (javascript creates a new property if it is not already existing in case of write operations, for read operations prototype chain is followed)
But surprisingly myCar.getName() still prints "Tesla" and not Corvette, because though the variable names are same they are in diffrent scope.The one that is referred by getName was part of Car function scope and is bounded to getName via Closure, but the name ("corvette") that you added belongs to new object that you created.
The purpose of "this" is to add the functions/variables defined inside constructor function to the object that you are going to create through that constructor function.
Hope it helps.

Another brick in the JS wall

I must confess, JavaScript has -sometimes- strange behaviors.
var Npc = function() {
this.name='Hello world';
}
Npc.attr='my new attribute';
console.log('>>>>'+Npc.attr); // my new attribute
console.log('>>>>'+Npc.name); // '' ????
var data = new Npc();
console.log('>>>>>' + data.attr); // undefined
console.log('>>>>>' + data.name); // Hello world
Sounds weird to me.
If I can understand the .name difference (instance vs literal), I cannot understand the "attr" behavior.
Is it a COW ? But with the node.js debugger I really see the attr atribute !?
Waw...
It's perfectly normal.
var Npc = function() {
this.name='Hello world';
}
is a function constructor,until you execute the function nothing happens and name doesnt exist,makes sense.
so at this point only attr is defined.
var data = new Npc();
console.log('>>>>>' + data.attr); // undefined
console.log('>>>>>' + data.name);
var data = new Npc(); returns a new object, makes sense because you are using new.
if you want to access attr you need to find a reference to Npc inside that new object
data.constructor.attr is where you will find attr
Edit
little mistake on data.constructor.attr corrected
If you're coming from a class-keyword language like Java or C++, then this might help you.
In JavaScript a function can be used as a constructor for an object, as you did here:
var Npc = function() {
this.name='Hello world';
}
var data = new Npc();
By way of loose analogy to a class-keyword language, the "name" property is an instance variable defined in a "class" called Npc. So the expression data.name is perfectly logical.
In JavaScript a function is also an object, which is how you used it here:
Npc.attr='my new attribute';
Again by way of loose analogy to a class-keyword language, Npc.attr is like a static class member. So attr is a member of Npc and not a member of any instance of Npc.
Nothing strange here.
attr is the attribute of Npc function.
name is the attribute of object created when Npc is used as a constructor.
Therefore Npc function has no attribute name and object created by Npc has no attribute attr.
Don't confuse constructor function with objects it produces. If you want property to automatically propagate to all created objects - prototype it:
Npc.prototype.attr='my new attribute';
var data = new Npc();
console.log('>>>>>' + data.attr); // 'my new attribute';
In your 1st call you call Npc() directly (i.e not as a constructor). In this case the this inside the body of the function refers to the global object, which in your browser is the window object and in node is the global object. Either way, you assigned the .name property to the global object and thus you cannot see it as a property of the function object (don't forget that functions are ordinary objects as well in JavaScript and unless used with the new operator, they are not constructors)
In the 2nd case you actually use the function as a constructor since you use it in conjunction with the new operator. Here the this.name=... inside the body actually adds a name property to the newly instantiated object of type Npc. It is the magic of the new operator that gives the meaning of "the instantiated object" to the "this" keyword in the 2nd case.

JavaScript function binding (this keyword) is lost after assignment

this is one of most mystery feature in JavaScript, after assigning the object method to other variable, the binding (this keyword) is lost
var john = {
name: 'John',
greet: function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
};
john.greet("Mark"); // Hi Mark, my name is John
var fx = john.greet;
fx("Mark"); // Hi Mark, my name is
my question is:
1) what is happening behind the assignment? var fx = john.greet;
is this copy by value or copy by reference?
fx and john.greet point to two diferent function, right?
2) since fx is a global method, the scope chain contains only global object. what is the value of this property in Variable object?
john.greet("Mark") actually calls a function. When you do var fx = john.greet;, you're getting a reference to the function. So when you call it, this is not bound to john. What you're actually doing is window.fx("Mark") and so this is the window object. You were on the right track when you said that it was in the global context. In this particular instance, the global object is window, and so fx is actually window.fx.
When you have a function reference you should use call or apply if you want to set the value of this. Try doing this:
fx.call(john, "Mark");
The first argument in call or apply is the value used for this in the context of the function call.
EDIT
Some people mentioned that the real issue here might be confusion surrounding an object literal vs. an instance of an object. You're creating an object literal which also behaves kind of like a singleton. You cannot create a new instance of that object. In this case john is a reference to that object literal. In that context, this in the function greet refers to the object literal itself. Hence when you call john.greet("Mark"), this is bound to john.
When you grab a reference to john.greet just by itself and assigning it to a global variable, you're essentially doing this:
var fx = function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
In this scenario, this is window, because fx is basically window.fx (since the global object here is window. Assuming this code was wrapped inside another function, then the global object would refer to that function.
If you want to create multiple instances of an object, you can do something like this:
var Person = function(name) {
var self = this; //maintains a reference to the instance
this.name = name;
this.greet = function(name) {
alert("Hi " + name + ", my name is " + self.name);
}
}
var john = new Person("John");
john.greet("Mark"); // alerts "Hi Mark, my name is John"
var fx = john.greet;
fx("Mark"); // also alerts "Hi Mark, my name is John"
Here, the self variable (which is local to the function) maintains a reference to the actual instance because you're binding it to this when you create the object.
There are many best practices associated with OOP in Javascript. You can Google and find out (there are many links). I recommend reading stuff from Douglas Crockford especially.
1) fx and john.greet are referring to the same function object, the assignment operation for objects, works by reference.
For primitive values, like String, Number, Boolean undefined or null, a copy of the value will be made.
2) The this value refers to the global object.
The this value is not a property of the Variable Object and it has nothing to do with the scope chain, is a special reserved word, and it is determined implicitly when a function is called (you can also set it explicitly via call or apply).
JavaScript internally handles a Reference type, which consists of two components, the base object and the property name, when a function is invoked, the this value is determined implicitly by getting the base object (by the internal GetValue operation).
And finally, the last case where this is set implicitly is when you invoke a function with the new operator, the this keyword will refer to a newly created object.
So in brief, here is how this works implicitly:
1- When a function is called as a method (the function is invoked as member of an object):
obj.method(); // 'this' inside method will refer to obj
2- A normal function call:
myFunction(); // 'this' inside the function will refer to the Global object
// or
(function () {})();
3- When the new operator is used:
var obj = new MyObj(); // 'this' will refer to a newly created object.
As I understand it, you're only assigning that method to the variable "fx." The context of the john object doesn't come along with it.
Off the top of my head, "this" in the context of fx will refer to the global object, which in the context of a browser is (I believe) equivalent to your window object.
(editing to clarify global object. Sort of)
Because you're only setting fx to the greet method and not the entire john object, it has no concept of it's parent and becomes globally scoped. So in essence, it's passing by value in that in only copies the method.
Since the function is now globally scoped, "this" becomes the Window object.
If you instead set fx to john, you get what's expected.
var john = {
name: 'John',
greet: function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
};
john.greet("Mark"); // Hi Mark, my name is John
var fx = john;
fx.greet("Mark"); // Hi Mark, my name is John
inspired by #Vivin Paliath answer, actually I come out something new. As to me, I always try my best to make javascript programming the same way as java, especially in OOP.
So my suggestion is to avoid using this as possible as we can , when we first do
var self = this;
we should use self instead of this in all function (prototype function, whatsoever), but if we write something like this:
function MyObject = {
var self = this;
};
MyObject.prototype = {
method1 = function(data){
self.data = data;
}
}
This is not gonna work, because prototype is an object in MyObject, It can not access private member self owned by MyObject. My solution for this is simple:
function MyObject = {
var self = this;
MyObject.prototype.method1 = function(data){
self.data = data;
};
}
This takes the advantage of prototype's efficiency and also we do not have to care about all the this issues. Though we gonna type a lot of MyObject.prototype.xxxx thing.
If this helpful to your guys, please give me some thumb up, so I can gather 15 reputation to thumb up others, thanks.

Categories