i have a question about JavaScript!
I've been studying JavaScript for a few days, but it wasn't that hard cuz i alread have a lot of knowledge from Java. I have programmed for long time until now. I work with objects and i wanted to add a function to the object. But that funcion doesn't work properly...
Code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function person(name){
this.name = name;
}
function printName(){
return this.name;
}
var joza = new person("Josip");
</script>
</head>
<body>
<script type="text/javascript">
document.write(joza.printName());
</script>
</body>
</html>
So this code is supposed to use the object's function and print out it's name...
But... all I get is just a blank webpage!
Please help!!
Thank you!!
You got some brutal answers, but the one with a lexical closure seems to be missing. So here you are:
function Person(name){
this.printName=function(){
console.log(name);
};
}
test=new Person("John");
test.printName();
The thing is that JavaScript functions retain the environment where they were declared. So here the inner function can access local variables of the outer function, even when the outer function is not running any more. Actually it is similar to accessing final local variables from anonymous inner classes in Java, just these variables do not have to be final (so it would be perfectly possible to provide a setName method, which would alter the same name variable).
It is not very important/interesting for this particular use case, but this is a common way how you can get parameters into callback methods for example.
And the best part for confusion:
Your original code can be used too. JavaScript is not very picky about "this", you can invoke any method on any object:
function Person(name){
this.name=name;
}
function printName(){
console.log(this.name);
}
test=new Person("Jane");
printName.call(test);
Functions are objects, and they have a call method. Where the first argument sets this, and the rest are just passed as arguments for the method itself. For completeness: there is an apply method too, where the arguments for the function are passed as an array.
This is not very important here either, however a thing you should keep in mind is that this is not necessarily the object you expect. Yet again callback methods: if you use an object method as a callback, when the browser invokes it, this is usually the window object.
Ignoring the HTML for now here is your code:
function person(name){
this.name = name;
}
function printName(){
return this.name;
}
var joza = new person("Josip");
joza.printName() // Error
So what's going on above is that you are creating this person constructor function and then another function outside of it. Your joza object does not have the printName function on it.
The printName function is just a regular function that has its own context for this, which in this case is just the window.
When you call joza.printName you will find that printName doesn't exist on the joza object you just created.
Try this instead by adding your printName method to the actual returned person object:
function person(name){
this.name = name;
this.printName = function() {
return this.name
}
}
var joza = new person("Josip");
joza.printName() // "Josip"
Just a minor change (you're trying to call the printName method of the person object).
function person(name){
this.name = name;
this.printName = function() {
return this.name;
}
}
var joza = new person("Josip");
document.write(joza.printName());
check this revision :
var person = function(name){
var tmp = {};
tmp.name = name;
tmp.printName = function(){
return tmp.name;
}
return tmp;
}
var joza = new person("Josip");
Fiddle : https://jsfiddle.net/jwvvkgaf/
This is a factory pattern, one of the way to accomplish what you want.
If you want simple constructor pattern :
var person = function(name){
this.name = name;
this.printName = function() {
return this.name;
}
}
Here's the way to add object like java in javascript
function person(name){
this.name = name;
}
Add methods like this. All Person objects will be able to invoke this
person.prototype.printName = function(){
return this.name;
}
Instantiate new objects with 'new'
var joza = new person("Josip");
Invoke methods like this
joza.printName();
<html>
<head>
<script type="text/javascript">
function person(name) {
this.name = name;
this.printName = function() {
return this.name;
}
}
var joza = new person("Josip");
</script>
</head>
<body>
<script type="text/javascript">
document.write(joza.printName());
</script>
</body>
</html>
The
function printName(){
return this.name;
}
is not a member of Person ,so you can get the name property from it, you should put the method inside the pesron object
(function(global){
function person(name){
this.name = name;
}
person.prototype ={
printName: function(){
return this.name;
},
};
window.person = person;
}(window));
var joza = new person("Josip");
document.write(joza.printName());
Let me break it down for you. (function(){ /* code in here */ }()) this is a scope. Basically kind of like a namespace so you don't pollute the window global variable. Then you declare the function person which is more or less your "constructor" that constructor initializes the property name. Then, put your functions inside the prototype and call them.
Related
The title is probably confusing but I will use a code snippet so hopefully you can explain what's going on.
My constructor
function Person(name, age){
this.name = name;
this.age = age;
this.yearsToRetire = function(){
console.log(this.age); //undefined
return 65-this.age;
}();
}
var joe = new Person ("joe",26);
console.log(joe.yearsToRetire); //NaN
My question is how come it doesn't know the value of this.age when I have already passed it and it should be 26 at the time of execution of yearsToRetire? Is it possible to achieve the effect of getting the years until retirement as the return value rather than a function to execute?(i.e is there a way that I use joe.yearsToRetire to get 39 rather than joe.yearsToRetire())
Thanks
this within the function refers to the global window object or undefined in strict mode, not the Person. One solution is to use an arrow function with lexical this:
function Person(name, age) {
this.name = name;
this.age = age;
this.yearsToRetire = (() => {
return 65 - this.age;
})();
}
var joe = new Person("joe", 26);
console.log(joe.yearsToRetire); // 39
Of course, the simpler solution here is to get rid of the immediately invoked function expression (IIFE) and write this.yearsToRetire = 65 - this.age;
Alternatively, add yearsToRetire as a function to the prototype:
Person.prototype.yearsToRetire = function() {
return 65 - this.age;
}
Or just remove the immediate invokation, as suggested by #ScottMargus - depending on what you want to achieve.
There are multiple problems. First you are invoking your function when you declare it which is putting the value of yearsToRetire as NaN. So remove the () at the end of your yearsToRetire function declaration. Second, you then need to call your function as a function: joe.yearsToRetire() instead of joe.yearsToRetire.
function Person(name, age){
this.name = name;
this.age = age;
this.yearsToRetire = function(){
return 65-this.age;
};
}
var joe = new Person ("joe",26);
console.log(joe.yearsToRetire());
You can call the function in the Person's scope using call or apply or simply
save a reference to the person object:
function Person(name, age){
var self = this;
this.name = name;
this.age = age;
this.yearsToRetire = (function(){
console.log(self.age);
return 65-self.age;
})();
}
var joe = new Person ("joe",26);
console.log(joe.yearsToRetire);
You have three issues:
You were self-invoking the function
You weren't calling for the yearsToRetire function to run, you were just referencing it.
Methods generally are added to an object's prototype so that each new instance doesn't have to store the same functionality over and over again.
Now, as for #1 (above), function declarations are hoisted to the top of their enclosing scope and are read into memory at the start of that scope's processing. When the function is read, if it includes other function invocations, those functions will be invoked and that return values of those functions will be used as the values for the function being read. That was your main problem. You thought that the self-invocation of yearsToRetire wouldn't happen until a new instance of Person was made, but in fact, that invocation was happening immediately.
This is not the pattern to use when creating constructor functions.
function Person(name, age){
this.name = name;
this.age = age;
}
// By adding the function to the prototype, each Person instance
// will inherit the method.
Person.prototype.yearsToRetire = function(){
console.log("The passed age was: " + this.age);
return 65-this.age;
}; // <-- You were self-invoking the function here
var joe = new Person ("joe",26);
console.log(joe.yearsToRetire()); // <-- You didn't include () after function name here
I am reading John Resig's slideshow http://ejohn.org/apps/learn/#78
Its not clear to me why i need to include .prototype in the line Me.prototype = new Person();
function Person(){}
Person.prototype.getName = function(){
return this.name;
};
function Me(){
this.name = "John Resig";
}
Me.prototype = new Person();
var me = new Me();
assert( me.getName(), "A name was set." );
Think of it this way, if every person is going to have a name, it's easier to assign the getName function to it's prototype.
In this case, you have a Person that has a prototype function to get a name, and a few lines below you have a Me function that assigns a name by default. Since we want to incorporate the getName function, we use the Person which already has that function object built-in. When you construct Me() and assign to me you can call getName() and use that to return the name, which by default is "John Resig"
The same thing can be achieved without prototype, like this
function Me(){
this.name = "John Resig";
this.getName = function () {
return this.name;
}
}
var me = new Me();
...BUT by using prototype, it helps create objects a lot faster, you can refer to this answer as well.
I have this code:
function Person(name){
var self = this;
this.name = name;
function hello(){
alert("hello " + self.name);
}
return {
hello: hello
};
}
var newPerson = new Person("john");
newPerson.hello();
I want to be able to use the 'this' keyword to access the 'name' property in the 'hello' function; I want an alternative to using the 'self' variable.
Except using the $.proxy function of jquery to control the context, how can I write the same code but without the variable 'self'?
I want a code that looks like below but 'name' is always 'undefined' when I call 'newPerson.hello()'. I don't know why because I have always believed that the scope of a function is always the object at the left of the dot of the caller and in this case, it's 'newPerson' that have been assign a value 'john' when creating the object.
function Person(name){
this.name = name;
function hello(){
alert("hello " + this.name);
}
return {
hello: hello
};
}
var newPerson = new Person("john");
newPerson.hello();
Thank you.
You can use .bind to force the owner of a function to be whatever object you pass. So, you can write your Person object like so:
function Person(name){
this.name = name;
var hello = function(){
alert("hello " + this.name);
}.bind(this);
return {
hello: hello
};
}
This will ensure that .hello always executes in the context of the Person that is calling it.
Here's a demo:
--- jsFiddle DEMO ---
Don't use return by default when using the new keyword the function will return this
you will need to change how your function is declared how ever.
Here is a fiddle
http://jsfiddle.net/SaintGerbil/9SAhD/
function Person(name){
this.name = name;
this.hello = function (){
alert("hello " + this.name);
}
}
var newPerson = new Person("john");
newPerson.hello();
EDIT if you require name to be private then here is an alternative
function Person(name){
var _name = name;
this.hello = function (){
alert("hello " + _name);
}
}
var newPerson = new Person("john");
newPerson.hello();
In answer to your question there are 4 ways to call a function
These affect the value of this they are
Constructor call (using the new keyword) where this is the new object which is returned automatically.
Method call if a function is attached to an object and called from it then this is the object called from.
Function call a direct call to a function will result in this being the global object, (a common mistake when calling a contstructor without new)
Apply\Call call when using a method to specify what this should be (see jackwanders as an example)
FURTHER EDIT
So taking your desired code at the start and explaining what is happening.
function Person(name){
this.name = name; // 1
function hello(){ // 2
alert("hello " + this.name); // 3
}
return {
hello: hello
}; //4
}
Person as a function can be called two ways:
var x = Person("ted");
and
var x = new Person("jimmy");
Since you have named Person with a capital it implies that you are expecting people to use new.
So sticking with that we enter the function and javascript creates a new object and assigns it to this.
line 1 we then attach a 'name' variable to this and initialise with the passed parameter.
line 2 we then attach a 'hello' function to this.
line 3 the function expects to have a 'name' variable exist attached to this (which it does for now).
line 4 rather than return this (default behavior) we are now declaring a new object and attaching the function to it. This new object does not have a 'name' variable with in its scope.
So when you create the object you get an object with a function attached but it cannot get to the variable it needs to execute correctly.
Which is why you are getting the undefined.
Does that make sense I always worry that I'm waffling when I have to expand the textbox?
Or if I wrote out your function as verbosely as possible it would look something like this.
function Person(name){
var this = new Object();
this.name = name;
var hello = function (){
alert("hello " + this.name);
}
this.hello = hello;
var that = new Object();
that.hello = hello;
return that;
}
You appear to be confusing two things.
a) Regular functions
function CreatePerson(name) {
// create a new object
var person = {};
// or (if you want to provide a prototype)
var person = Object.create(...);
// fill it with some more data
person.name = name;
person.foo = 123;
person.bar = function() { /* ... your method body ... */ };
}
That's invoked like:
var person = CreatePerson("Jack");
b) Constructors
function Person(name) {
// called after a Person is created,
// `this` is bound to the new object
// and its prototype is set to `Person.prototype`
this.name = name;
this.foo = 123;
this.bar = function() { /* ... your method body ... */ };
}
var person = new Person("Jack");
Note the special new syntax here.
When using this style, you'll probably want to create the methods only once, not for every created instance:
function Person(name) {
// called after a Person is created,
// `this` is bound to the new object
// and its prototype is set to `Person.prototype`
this.name = name;
this.foo = 123;
}
Person.prototype.bar = function() {
/* ... your method body ... */
};
var person = new Person("Jack");
Doing like this works.
If you only want to access the this within the function you can do like this.
you use the return {hello:hello} to declare the function and you don't need do to it, unless it's what you want
example 1
function _persons(array) {
this.available = array;
this.write = function () {
writedata(this.available, '#array2');
};
this.SortAge = function () {
array.sort(compare);
writedata(this.available, '#array3');
};
array.sort(compareName);
}
var users = new _persons(myarray);
example 2
function Person(name ){
this.name = name ;
this.hello = function(){
alert("hello " + this.name);
}
}
var a = "john";
var newPerson = new Person(a);
newPerson.hello(); var
otherPerson = new Person("annie");
otherPerson.hello();
<html>
<head>
<script type="text/javascript">
function Person (name, age) {
this.name = name;
this.age = age;
this.sayName = function () {
alert(this.name);
}
}
var person1 = new Person ("tom", 29);
var person2 = new Person ("frank", 21);
alert(person1.sayName==person2.sayName);
</script>
</head>
<body>
</body>
</html>
There is nothing wrong with it (other than the slightly pedantic missing semicolon on line 6.)
Because the sayName function is created inside the constructor, a new function is created every time a new object is created. (So the functions are different, and == returns false)
People get around this by attaching the function to the prototype object instead:
function Person (name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function () {
alert(this.name);
};
var person1 = new Person ("tom", 29);
var person2 = new Person ("frank", 21);
alert(person1.sayName==person2.sayName);
This will create only one function (saving you memory) and the alert will say 'true'.
You are comparing the function pinters, not the results.
Try:
alert( person1.sayName() == person2.sayName() );
But then again: your sayName() triggers another alert(). What is this code all about??
person1 and person2 are different objects, so their comparison should be false.
However, you may have meant to compare the functions literally, which you can with toString(), in which case, the alert is true.
jsFiddle.
And of course, they both have a different this.name so if they did return that, and you called the functions and compared them, it would be false as well.
function Person(name) {
this.name = name;
this.say = function() {
console.info('I am ' + this.name);
}
}
var p=new Person('stackoverflow');
Someone tell me that the above codes are equals to :
function Person(name) {
this.name = name;
this.say = function() {
console.info('I am ' + this.name);
}
}
var p={};
Person.call(p,'stackoverflow');
Is this true?
If so, how about the prototype?
Each object in javascripte owns a prototype,and the prototype chain hold the releationship of the obejcts,I wonder if this prototype does something or not.
In this example, when the object of 'p' is created,does it call some build-in method of the superclass of Person?
BTW,what I want to know is what does the syntax var p=new Person('stackoverflow'); do ?
-----------------update------------------
function Person(name) {
this.name = name;
}
Person.prototype.say = function() {
console.info('I am ' + this.name);
}
How about if I put the defination of say inside the person function:
function Person(name) {
this.name = name;
Person.prototype.say = function() {
console.info('I am ' + this.name);
}
}
The code:
var p=new Person('stackoverflow');
creates a new instance of the Person class. You must remember that classes in javascript are functions, so when you call:
Person.call(p,'stackoverflow');
You are just calling the Person function and binding it to the p object (this means that in the function context the this will refer to the p object). Those pieces of code do the same thing, except for the fact that the first is an instance of the class so if you update the prototype object of person its properties will be updated.
Anyway the situation is different when you fill the prototype object of the Person function:
Person.prototype={test:"test"}
If you add this after the Person function declaration you will see that those pieces of code have a different behaviour. The object initialized with "new" will contain the test property, but the other one hasn't it. This happens because the prototype object is applied only to the instances of the class when using "new".
Well, actually
var p=new Person('stackoverflow');
is equivalent to:
var p={};
p.__proto__ = Person.prototype;
Person.call(p,'stackoverflow');
except that __proto__ is not standard JavaScript (but is supported by
some implementations).