Some basic questions about OOP in JS - javascript

currently I´m learning about objects and I´m not sure about the terminology of some words and descriptions. I´m sure some of you can help me out here :)
Code example:
function Person(name) {
this.name = name,
this.introduce = function() {
console.log("My name is " + this.name);
}
}
var jon = new Person("Jon")
jon.introduce();
My questions:
Is there actually a difference between the code above and the following code:
var Person = function(name) {
this.name = name,
this.introduce = function() {
console.log("My name is " + this.name);
}
}
var jon = new Person("Jon")
jon.introduce();
Which one is better practice? I guess the first code snippet, since it´s less code.
Now the terminology.
2.1 Am I right, given the code example at the beginning, that you call the following snippet the Prototype?
function Person(name) {
this.name = name,
this.introduce = function() {
console.log("My name is " + this.name);
}
}
2.2 Am I right, given the code example at the beginning, that you call the following snippet the constructor(-function)?
var jon = new Person("Jon")
Thanks and happy eastern! :)

Point 1: The big Words
function Person(name) {
this.name = name,
this.introduce = function() {
console.log("My name is " + this.name);
}
}
var jon = new Person("Jon")
jon.introduce();
This function has a name 'Person'. This is called a Function statement.
var Person = function(name) {
this.name = name,
this.introduce = function() {
console.log("My name is " + this.name);
}
}
var jon = new Person("Jon")
jon.introduce();
This funciton is anonymous and does not have a name. We can assign a name but
it is not required since the variable can be used to execute the function. This is called a function expression.
You can read more about Function statements and expressions here:
https://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
Point 2: Execution (Hoisting)
Functions assigned to variable must be called after the function is defined because of the way hoisting works.
So for the first case the function can be called either below or above it is defined.
But for the second case the function must be invoked after it. Since it is stored in a variable. Invoking it before the function will return undefined. It won't give error. The variable is there in memory space but it is not defined at that point.
You can read more about variable and function hoisting here:
http://adripofjavascript.com/blog/drips/variable-and-function-hoisting
Point 3: Function constructor:
In your case the term to use for function is "Function Constructor" since you are essentially using function as a constructor for the Person object to define it's properties.

It's simply the difference between a function expression vs. declaration. I would go with the seemingly simpler declaration instead of the unnamed anonymous function assigned to a variable.
That snippet shows the constructor function also returned by jon.constructor. The prototype of a person constructed by that constructor function - which you can access via Object.getPrototypeOf(jon) or Person.prototype - is pretty much empty. Assigning this.name = name doesn't add a name attribute to the prototype but the currently created object.
It's the new operator applied to a constructor function returning a newly constructed object.

Related

Javascript: lexical scoping issue using new keyword constructor

i have problem about scoping in javascipt. I tried to create new object using the "new" keyword without any problem. The code looks like this
"use strict";
function Person() {
this.name = "john doe";
console.log(this.name);
}
Var foo = new Person()
The problem i encountered is when i try to add inner function the scope of the name variable becomes undefined inside the inner function
"use strict";
function Person() {
this.name = "john doe";
Function speak() {
console.log("my name is" + this.name);
}
speak();
}
var foo = new Person();
//error: "cannot read property 'name' of undefined"
Can somebody explained what seems to be the problem? Thank guys
With Strict mode when you are creating the object with new Person(), this refers to the window object which does not have the property called name. property called name belongs to the Person object.
Thus you are getting error cannot read property 'name' of undefined.
User another variable to hold the value of Person object's this to use that inside the inner function.
var thatObj = this;
"use strict";
function Person() {
this.name = "john doe";
var thatObj = this;
function speak() {
console.log("my name is: " + thatObj.name);
}
speak();
}
var foo = new Person();
You can also give speak the same scope as this. It should be noted that this will also make it a public function, so speak can be called from outside of the Person class.
function Person() {
this.name = "john doe";
this.speak = function() {
console.log("my name is " + this.name);
};
this.speak();
}
var foo = new Person();
this is determined by how a function is invoked, not where the function is defined. Since this.name is inside its own scope it has lost a reference to this.name instead it is referencing a global window object.
It is important to be aware of the fact when using this keyword inside of nested functions you are more than likely going to lose reference to the object that you are inside of and your this keyword will end up referencing the global object.
There is also another solution to your example using call or apply methods.
call and apply will allow you to change the value of this when function is executed.
'use strict';
function Person () {
this.name = 'john doe';
function speak () {
console.log('my name is: ' + this.name);
}
speak.call(this);
}
var foo = new Person();

how does "new" work with classes in javascript?

How does the new work differently in the 2 examples below? I see that the 2nd example is replacing the annoymous funciton with a variable, but in the second one, the function/class "Person" is actually being called. Does it make any difference if it's being called or not? I tried it without the calling and it still worked. So that led me to believe that new is actually calling the function and setting up this to be assigned to the instance variable.
var person = new function() {
this.setName = function(name) {
this.name = name;
}
this.sayHi = function() {
return "Hi, my name is " + this.name;
}
}
person.setName("Rafael");
console.log(person.sayHi()); // Hi, my name is Rafael
var Person = function() {
this.setName = function(name) {
this.name = name;
}
this.sayHi = function() {
return "Hi, my name is " + this.name;
}
}
var personTwo = new Person()
personTwo.setName("Rafael");
console.log(personTwo.sayHi()); // Hi, my name is Rafael
There would be almost no difference between these two examples, if it was a simple function like this:
(function() { console.log("IIFE"); })();
// or
var f = function() { console.log("Function"); };
f();
You just store your function in a variable, and then call it.
However, it makes a little difference, since it is related to JS OOP mechanisms. In the first case you get Object instance, and in the second you get Person instance. This makes difference in OOP sense.
var person = new function() { };
console.log("Is instance of: " + person.constructor.name);
console.log("There is no way to check instanceof in this case");
var Person = function() { };
var person = new Person();
console.log("Is instance of: " + person.constructor.name);
console.log(person instanceof Person);
In general, new and classes are supposed to be used as in the second case in order to enable the full functionality of JS OOP. There is absolutely no sense or/and advantage in using anonymous class constructor.
Whether or not it is assigned into a variable: does not matter. It is completely parallel to this example:
var x = 1;
console.log(x);
and
console.log(1);
Whether it needs to be called or not: A function with the new operator is always being called, but with new, parentheses are optional when no parameters are passed: new Person() is equivalent to new Person, but new Person("Joe") cannot be done differently.
In the second example, you are passing to the new operator the exact same function. You simply are using a reference (logically stored in a variable) instead of writing literal function just in place.
So, your second example is the same as:
var personTwo = new (function() {
[...]
})()
[...]
Which, in fact, is much the same as the first one:
var person = new (function() {
[...]
})
[...]
NOTE that the parentheses surrounding the function are absolutely optional in this case. You could be placed there seven if you like: (((((((function(){[...]}))))))).
The point here is that when you say «in the second one, the function/class "Person" is actually being called» you are WRONG there: That function, which acts as a constructor isn't being called by you. You are simply passing it as a parameter (the constructor function) of the new operator which is, in fact, who is actually calling the constructor with the rest of parameters you provided, if any.
See new syntax documentation:
new constructor[([arguments])]
The constructor is the function you pass to the new operator and the parameters are specified between parentheses. But they are fully optional (including the parentheses itself).
This is why new constructor; without parentheses works.
To be clear: What you thought happens (but not) would be written as:
var person = new ((function(){...})()) ();
...or, more verbosely:
var person = new (
(function(){ // Constructor builder.
[...]
return function(){...}; // Actual constructor.
})() // Constructor builder call
//v-- Parentheses to force builder to be called.
) (); // <-- Parameters (if any) passed to the constructor.

differences between defining functions/methods in JS?

Here are 3 ways to address the key-value pair of objects constructed using constructor. What are the differences among these 3 ways in every describable aspects? (I would even like to enquiry about basic differences between function & method in terms of their functionality, usage, etc.)
function Person(name,age) {
this.name = name;
this.age = age;
}
var bob = new Person("Bob Smith", 30);
var me = new Person('Madhav Devkota', 55);
//===================================================
//A. Simple function
printPerson= function (p) {
console.log(p.name);
};
printPerson(bob); printPerson(me);
//===================================================
//B. Method I
printPerson = function(){
console.log(this.name) ;
};
bob.printPerson = printPerson; me.printPerson = printPerson;
bob.printPerson(); me.printPerson();
//=================================================
//C. Method II
this.printPerson = function() {
console.log(this.name);
};
bob.printPerson(); me.printPerson();
I would also add
// 0. No function
console.log(bob.name);
console.log(me.name);
It is the most basic way. You are doing something with you object properties directly.
A. Simple function
You are giving your code a name to improve semantics. Now you are describing what your code is intended to do.
You can access more properties and combine to create complex result without code repetition.
printPerson = function (p) {
console.log(p.name + ' is aged ' + p.age)
}
instead of No function
console.log(bob.name + ' is aged ' + bob.age);
console.log(me.name ' is aged ' + me.age);
B. Method I
Now your function is also a property of your object. Unlike simple function which works in scope where it is declared, your method it attached to your object and you can pass it around along with it. When invoked 'this' references the object from which method is invoked.
You can also do a 'nonsense' method like this:
printPerson = function(p){
console.log(p.name) ;
};
bob.printPerson = printPerson; me.printPerson = printPerson;
bob.printPerson(bob); me.printPerson(me);
C. Method II
This one is not quite right. It doesn't make sense in given context as 'this' is at that moment referencing Window object. At then end you are actually calling 'Method I' methods again.
Correct way to use it is in constructor function:
function Person(name,age) {
this.name = name;
this.age = age;
this.printPerson = function() {
console.log(this.name);
};
}
Now your objects have .printPerson() method as soon as they are created.
I could elaborate more if you wish but it's important to notice that function vs method difference is not too relevant at this level of code complexity. When your code gets more complex code organization becomes important. For 'next level' you should get more familiar with Javascript scoping and object inheritance.

Why compiler doesn't translate "this" link into context-agnostic variable?

Suppose I have a class (very simple scenario)
class Student
{
name = "John";
sayHello()
{
console.log("Hi, I'm " + this.name);
}
}
It's compiled by TypeScript compiler to:
var Student = (function () {
function Student() {
this.name = "John";
}
Student.prototype.sayHello = function () {
console.log("Hi, I'm " + this.name); //here is the problem. Accessing name via this
};
return Student;
})();
Now if I create an object and call a method, everything works fine.
var student = new Student();
student.sayHello(); //prints Hi, I'm John
But if I invoke that method from callback, it breaks (this is referencing a Window as expected)
setTimeout(student.sayHello); //prints Hi, I'm
I'm aware of the difference between this in JavaScript and C# or Java. I'm also aware, that TypeScript tries to address this difference. For example this code:
class Student
{
name = "John";
sayHelloTo(other)
{
other(() => this.name);
}
}
Would have been compiled to
var Student = (function () {
function Student() {
this.name = "John";
}
Student.prototype.sayHelloTo = function (other) {
//note, the compiler solves the problem by capturing this into local variable
var _this = this;
other(function () {
return _this.name;
});
};
return Student;
})();
Why isn't the compiler creates something like _this variable in the first scenario for class members? I would expect to see something along next code (not a real output and this code is not correct either, just to show my intention)
var Student = (function () {
var _this;
function Student() {
_this = this; //solves the problem of setTimeout(student.sayHello)
_this.name = "John";
}
Student.prototype.sayHello = function () {
console.log("Hi, I'm " + _this.name);
};
return Student;
})();
I've used the TypeScript v0.9.7 compiler
You might want to change the sayHello function like below to make it generate to code you want. Notice the sayHello = () => { }
This will still work with multiple students which is not the case with your example.
class Student
{
name = "John";
sayHello = () =>
{
console.log("Hi, I'm " + this.name);
}
}
It will generate code like this:
function Student() {
var _this = this;
this.name = "John";
this.sayHello = function () {
console.log("Hi, I'm " + _this.name);
};
}
Another possibility is to change the call to setTimeout like this
setTimeout(() => { student.sayHello() });
The only thing that the compiler could do would be to make sure each constructed object had a bound copy of the prototype functions. That would involve a very significant semantic change, so it can't really do that.
The translated code returns a function that has access to a closure, it's true. However, in your suggested alternative, there's only one _this that would be shared by all instances created by the constructor. The closure is in that function that is called to create the "Student" constructor; that function only runs once, when the constructor is made, and then never again. Thus each call to new Student() would update that single, shared variable _this. (In the example, the way that would cause a problem would be for the "name" property to change on a Student instance. If they all are named "John" it doesn't matter :)
The fundamental issue is that in JavaScript, there is no intrinsic relationship between a function and any object. When you call
setTimeout(student.sayHello, 100);
the first parameter expression evaluates to a plain reference to that "sayHello" function. The fact that the reference came from the object is lost. I suppose another alternative for Typescript would be to catch those sorts of expressions and create a bound function at that point. That is, the class code itself would remain the same, but the setTimeout() call would be translated as
setTimeout(student.sayHello.bind(student), 100);
What sort of ramifications that would have on everything I can't say. I also don't know how hard it would be for the compiler to know that it should do that transformation; there might be times at which it doesn't make sense.

Do functions attached to the prototype property not have closure

I am trying to figure out how I can add methods to a constructor after I have created it.
In my code below, I cannot use Person's prototype property to add a new public method which has access to Person's vars. (Do the functions attached to the prototype property not close over the vars in the main function).
Unlike the first way, the second way works - Person 2. seems like these are called privileged methods -http://www.crockford.com/javascript/private.html.
function Person(name, age){}
Person.prototype.details = function(){
return "name: "+name+", age: "+age;
};
function Person2(name, age){
this.details = function(){
return "name: "+name+", age: "+age;};
}
var per1 = new Person("jim", 22);
var per2 = new Person2("jack", 28);
per1.details();
//=> ReferenceError: age is not defined
per2.details();
//=> "name: jack, age: 28"
No, they do not have closure over the constructor functions vars. They are in a different scope.
// This function is in one scope.
function Person(name, age) {
}
// This statement is in the parent scope, which
// doesn't have access to child scopes.
Person.prototype.details = function(){
return "name: "+name+", age: "+age;
};
That's the way that "public" functions work in JavaScript. You could make details a privileged function by defining it within the constructor:
function Person(name, age) {
this.details = function() {
return "name: "+name+", age: "+age;
};
}
Of course, that means that each instance of Person gets it's own copy of the details function.
You could also, as #Chuck suggests, make name and age public members, in which you would have access to them in a prototype function:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.details = function(){
return "name: " + this.name + ", age: " + this.age;
};
No. Typically you would either use the second approach, or set this._name = name; in the constructor and reference it that way in the other method.
Of course not, the function was declared in a scope, different to the scope where the arguments/variables were declared, so JS wouldn't know which variables you're on about. Suppose you had a second closure, or better (well, worse actually) yet: a global variable called name. Which one would JS pick?
Here's an example for you:
function MyObject(name)
{
var localVar = 'foobar';
this.evilMethod = (function(localVar)
{
return function()
{
console.log('localVar = '+localVar);//=== name
};
})(name);
this.badMethod = function()
{
console.log('localVar = '+ localVar);// === 'foobar'
};
}
var name = 'Global Name';
var anotherClosure = (function(name)
{
var localVar = name.toLowerCase();
return function()
{
console.log(name);
console.log(localVar);
}
})('Bobby');
MyObject.prototype.closureVars = function()
{
console.log(name);//Global name
console.log(localVar);//undefined
};
Now first off: this is terrible code, but you get the point: you can have hundreds of variables with the same name, which one JS has to use, might not always be clear.
Giving prototypes access to instance closure variables has other implications, too: you could, for instance change their values, which defeats the point of having a closure in the first place. But the biggest problem by a country mile would be: multiple instances! If you create a constructor, odds are you're going to instantiate more than 1 object with it. How would that work, if they all share the same prototype?
Just assign the arguments/variables you want to access in the prototype to a property, like FishBasketGordo's example does

Categories

Resources