This question already has answers here:
What is the difference between a function expression vs declaration in JavaScript? [duplicate]
(5 answers)
Closed 7 years ago.
I am reading a JavaScript book and here the constructor function is created like this:
var Person = function (living, age, gender) {
this.living = living;
this.age = age;
this.gender = gender;
this.getGender = function () { return this.gender; };
};
And I read somewhere something like this:
function Person (living, age, gender) {
this.living = living;
this.age = age;
this.gender = gender;
this.getGender = function () { return this.gender; };
};
I wonder what the difference is between these two. Is there any difference when we create instances or are they the same, just two different ways of creating object constructors?
The first is a function expression, the second a function declaration (it doesn't need the semicolon at the end, btw). The distinction is not tied to constructors, however and applies to ordinary functions.
As you probably know, functions are first-class values in javascript. One of the things that implies is that functions can be assigned to variables. So, just like you can assign numbers to variables (e.g. var pi = 3.14), you can assign functions to variables, var add = function(a,b) {return a + b}. That's what your first declaration does, it creates a function (implemented as a closure) and then stores the reference to it in the variable Person. You can think of the second one as a shortcut for the first.
For the syntactical details, check out ยง14.1 of the spec.
Both are similar and you can create instances from them with new Person().
The only difference is that in the 1st case it's an expression ,so it must be defined before you use it while in the second case , due to hoisting you can use the function anywhere in your file
This is defined at run-time (function expression):
var Person = function (living, age, gender) {
this.living = living;
this.age = age;
this.gender = gender;
this.getGender = function () { return this.gender; };
};
And this is defined at parse-time (function declaration):
function Person (living, age, gender) {
this.living = living;
this.age = age;
this.gender = gender;
this.getGender = function () { return this.gender; };
};
As an example:
funA(); // does not work
funB(); // it works
var funA = function(){console.log("testA");}
function funB(){console.log("testB");}
funA(); // it works
funB(); // it works
Other StackOverflow reference that supports my answer --> var-functionname-function-vs-function-functionname
Related
I'm trying to learn JavaScript, but got stuck with a problem (more with misunderstanding "this" keyword) that doesn't give me move on.
I've watched a lot of content about it and barely understood it, but still have some troubles.
I have some code:
function Person (name, age) {
this.name = name;
this.age = age;
this.changeName = function (name) {
this.name = name;
}
}
What do we use "this" here for?
As I understood we use "this" to create variable inside function constructor and give it value of our "name" parameter that we could refer to it. Am I right?
Then I have this code:
var p1 = new Person ("John", 30);
p1.changeName ("Jane");
console.log(p1.name);
As I sorted out here, we call method that overwrites our variable that we created to refer to. But it doesn't change actual parameter. So if it's right why do we use it? Doesn't it matter to have actual "name" parameter changed?
The whole code is from teaching app!
So if it's right why do we use it? Doesn't it matter to have actual "name" parameter changed?
No, there's no need to do that in this example. changeName changes the property on the object that was created by new Person.
It's true that that example code is a bit odd, because it creates the changeName function in the constructor but doesn't do the kinds of things you'd normally do when you create the function in the constructor. I'd expect that code to either be this, which puts the changeName on the prototype:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.changeName = function(name) {
this.name = name;
};
(or the class equivalent) or this:
function Person(name, age) {
this.getName = function() {
return name;
};
this.changeName = function(newName) {
name = newName;
};
this.getAge = function() {
return age;
};
}
That code does update the parameter (which has no effect at all on the code calling Person). It doesn't create name and age properties at all; instead, it just makes their values accessible via getName and getAge. There's also a function to change name (changeName); but there's no function to change age. People write code like that so that age cannot be changed from outside code created within the Person constructor.
I guess you may misunderstand which parameter you actually change, so I rewrite it like so, holp this helps.
function Person (argument_name, argument_age) {
this.name = argument_name;
this.age = argument_age;
this.changeName = function (argument_change_name) {
this.name = argument_change_name;
}
}
let p1 = new Person ("John", 30);
p1.changeName ("Jane");
console.log(p1);
The this keyword is used to create and assign values to variables in the class. It is again used to create functions, either getters or setters. So in your code this.changeName is a function that when passed a value will change the name of the person.
eg.
var a = 5; // a is an integer
var b = "Han"; //b is a string
var c = function(name){
//code here
} // then c is also a function;
I am trying to review some basic Javascript using an online environment where print() is allowed. However, when I try to call say() on an instance of the person, it is saying that "say" is not a function. I have tried this in several different environments with their version of print (be it writeln, console.log, or whatever) and it's always saying it's not a function.
//JavaScript-C24.2.0 (SpiderMonkey)
print("Hello, world!")
function person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
print(this.name);
}
}
var arrayz = [];
arrayz.push(person("bob",20));
arrayz.push(person("sally",19));
arrayz.push(person("joe",22));
for (var z in arrayz) {
z.say();
}
I'm doing it in just the same manner as this is: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS
So I don't see what I'm doing wrong. Can someone please help me with what I'm doing wrong here?
The correct code should be:
print("Hello, world!")
function person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
print(this.name);
}
}
var arrayz = [];
arrayz.push(new person("bob",20));
arrayz.push(new person("sally",19));
arrayz.push(new person("joe",22));
for (var z of arrayz) {
z.say();
}
Let me explain. The first difference is the new keyword. This creates a new instance of the function you've made as an object. The way you did it just called person as a function. So it stores the returned value of person into the the array instead of the object instance. Since person doesn't return a value it stores undefined into your array.
More info about the new operator: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
Second, you used var z in arrayz. When using in, z becomes the index instead of the object. If you want the z to be the value of the array item you should use var z of arrayz
More info about for...in: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
More info about for...of: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
Solution :
Using new person(...) instead of person(...) will create the object you want, filled with properties you specified by writing this.xxx = yyy in the function body.
Explanation of your error :
You are simply calling the function, meaning that you are trying to get its the return value and push it in the array.
I don't see any return statement in your function person, so the result is undefined.
You have pushed 3 undefined in your array, and you try to execute say() on them.
In Javascript Koans, .beget() is used to, I suppose, allow a new prototype be created with identical traits? I'm hoping to clarify whether the Gonzo.prototype = Muppet.prototype.beget(); is what allows gonzo.answerNanny()); to work, or whether it's the Muppet.call(this, age, hobby);
function Muppet(age, hobby) {
this.age = age;
this.hobby = hobby;
this.answerNanny = function(){
return "Everything's cool!";
}
}
function Gonzo(age, hobby, trick) {
Muppet.call(this, age, hobby);
this.trick = trick;
this.doTrick = function() {
return this.trick;
}
}
Gonzo.prototype = Muppet.prototype.beget();
it("should be able to call a method on the base object", function() {
expect(this.gonzo.answerNanny()).toEqual("Everything's cool!");
});
The this.answerNanny function is a public priviledge function declared within the Muppet constructor. Since it's declared in the constructor and not on the Muppet.prototype then it's Muppet.call(this, age, hobby); that will add the answerNanny member to the Gonzo instance.
However, since the answerNanny function doesn't have to be priviledged (it doesn't access any variables that are private to the Muppet constructor) then it should really be defined on Muppet.prototype.
Finally, note that beget is not native JavaScript. I'm not sure to which implementation it refers here, but I believe it shall be similar to the one described by Crockford. The same can be achieved using Gonzo.prototype = Object.create(Muppet.prototype);
Is it possible to use the statement as shown below to define a method without the use of prototype?
Person.sayHello = function () {...}
On this example
var Person = function (firstName) {
this.firstName = firstName;
};
Person.prototype.sayHello = function() {
console.log("Hello, I'm " + this.firstName);
};
var person1 = new Person("Alice");
var person2 = new Person("Bob");
In short, no.
Person.sayHello = function () {...};
This line will add a function called "sayHello" to the Person class itself rather than to instances of the Person class. So, it can only be invoked by
Person.sayHello();
rather than by
var matt = new Person('Matt');
matt.sayHello();
// sayHello is not defined on matt
If you are familiar with Java or C#, adding a method to Person in this way is like creating a static method.
However, we can add a method to instances without adding a method to the prototype.
Method 1: Create the "sayHello" function in the constructor of Person
var Person = function (firstName) {
this.firstName = firstName;
this.sayHello = sayHello() {...};
};
This method has the disadvantage that a new function is created for every instance of Person. That is,
var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello != matt.sayHello;
Thus, this method can be hard on memory. However, it does allow for encapsulation (e.g. private state) via closures. In the following sample, it is impossible to modify the "count" variable outside of the Person class without calling the "sayHello" function.
var Person = function (firstName) {
this.firstName = firstName;
this.sayHello = sayHello() {
count++;
console.log("Hello has been said " + count + "times".
};
var count = 0;
};
Method 2: Create the "sayHello" function outside the constructor of Person and assign it within the constructor of Person
var Person = function (firstName) {
this.firstName = firstName;
this.sayHello = sayHello;
};
function sayHello() {...}
This method has the advantage of lower memory usage; there is only one instance of the sayHello function, and it is shared across instances of Person. That is,
var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello == matt.sayHello;
This makes it similar to the prototype method. However, the assignment of the function to each instance still consumes more memory than the prototype method where the function is only assigned to the prototype object.
However, like the prototype method, this method does not allow for private state. All state must be accessed through public state exposed via the this keyword.
Update: Clarification of the difference in memory usage between method 1 and method 2.
Method 1 is like this:
var function1 = function() { console.log('Hello'); };
var function2 = function() { console.log('Hello'); };
The functions have the same behavior, but are not equal. JavaScript doesn't know they are functionally similar, so it creates two functions in memory to represent them.
Method 2 is like this:
var sayHello = function() { console.log('Hello'); };
var function1 = sayHello;
var function2 = sayHello;
Now function1 and function2 are actually the same function because they both simply hold a reference to sayHello.
Update: Example usage of a module pattern to avoid adding "sayHello" to the global scope in method 2.
This module defines the Person class in a module defined by an anonymous closure (a self executing function) and exports it to the global scope. Because "sayHello" is defined in the closure of the module and is not exported, it is not added to the global scope.
var Person = (function () {
function Person(firstName) {
this.firstName = firstName;
this.sayHello = sayHello;
};
function sayHello() {...}
return Person;
}());
Yes, you can. If you come from traditional OO background, it might help to think about this as effectively behaving like a public static property on a class.
As jsdeveloper said in the above comment. Functions are just objects that can be executed. You can add properties to them just like any other object. This technique is actually used in practice for patterns like memoization or currying.
In your case sayHello can accessed anywhere the Person function can be accessed. It's not really related to inheritance/prototype since it doesn't have to do with resolving properties by traversing the prototype chain, but it is another way to make data accessible.
I'm sure it varies based on the developer, but I often put pure functions which don't reference this as static methods as you have done since they are easier to test and make the intention clear to other developers
It would be weird, but if you really need to do it that way, you can assign the function to its own prototype once, then add all of the functions to the main function.
var Person = function (firstName) {
this.firstName = firstName;
};
Person.prototype = Person;
Person.sayHello = function() {
console.log("Hello, I'm " + this.firstName);
};
Yes you can but the sayhello function will not be able to access any of the object properties (ie this.myvar) and you can only call it like a static method:
Person.sayhello()
(and not mypersonobject.sayhello).
When you extend the prototype, the sayhello function is available to all Person objects created using the 'new' keyword in the usual fashion.
https://jsfiddle.net/jsheridan390/kL7arrqs/
For example, compare these two:
function Person(name) {
this.name = name;
}
var john = new Person('John');
console.log(john.constructor);
// outputs: Person(name)
var MyJSLib = {
Person : function (name) {
this.name = name;
}
}
var john2 = new MyJSLib.Person('John');
console.log(john2.constructor);
// outputs: function()
The first form is useful for debugging at runtime. The 2nd form requires some extra steps to figure out what kind of object you have.
I know that I could write a descriptive toString function or call the toSource method on the constructor to get some more information, but I want the simplest way possible.
Is there a way to do this? Suggestions?
Well that happens because you are using an anonymous function.
You can specify names of anonymous functions (yes, it sounds odd), you could:
var MyJSLib = {
Person : function Person (name) {
this.name = name;
}
}
var john2 = new MyJSLib.Person('John');
console.log(john2.constructor);
Anonymous functions can be named but those names are only visible
within the functions themselves, and since you use the new operator, the constructor property will be set, and you will be able to see the name.
You could also compare the constructor reference using or not a name for the function:
console.log(john2.constructor === MyJSLib.Person); // true
If you want to check whether an object is instance of a specific class then simply use "instanceof" keyword to check that. If you explicitly want a name for the constructor(which I really cannot see a point) you may try the code below
var MyJSLib = {
Person : function Person(name) {
this.name = name;
}
}
what you want is the name of the holder in the namespace so.
function getName(namespace, obj) {
for name in namespace:
if (namespace[name] == obj) return name;
}
console.log(getNameOf(MyJSLib, john2.constructor));