Why I am getting undefined in browser while using document.write() ?
<script type="text/javascript">
function Person (name) {
this.name = name;
this.greeting = function() {
document.write("Hello " + name + " Go rock the industry!!");
};
}
var person1 = new Person("Sara");
var person2 = new Person("Bob");
document.write(person1.name + "<br>");
document.write(person1.greeting() + "<br>");
document.write(person2.name + "<br>");
document.write(person2.greeting() + "<br>");
</script>
In browser I get this output:
Sara
Hello Sara Go rock the industry!!undefined
Bob
Hello Bob Go rock the industry!!undefined
You are trying to use document.write on a function that does not return a value, rather performs document.write itself. Person.greeting() should return a value so you can use it when calling document.write(person2.greeting()).
It should be something like this:
function Person (name) {
this.name = name;
this.greeting = function() {
return ("Hello " + name + " Go rock the industry!!");
▲
};
}
You need to update the greeting function to return a string instead of calling document.write() itself.
Currently, the greeting function is calling document.write() and then implicitly returning the value undefined.
When you evaluate the expression
personX.greeting() + "<br/>"
it evaluates to
undefined + "<br/>"
and, according to the rules of JavaScript string concatenation, undefined is first cast to the string "undefined" and then concatenated with the next value.
Edit:
If you're interested in exploring property getter functions, you could also refactor as
function Person (name) {
this.name = name;
Object.defineProperty(this, 'greeting', {
get: function() {
return "Hello " + this.name + " Go rock the industry!!";
}
});
}
var person1 = new Person("Sara");
var person2 = new Person("Bob");
document.write(person1.name + "<br>");
document.write(person1.greeting + "<br>");
document.write(person2.name + "<br>");
document.write(person2.greeting + "<br>");
Notice how we can then access the computed value personX.greeting as if it were just a string property.
Depending on your environment, etc., if you can use ES2015+ syntax, you could achieve the same result with
class Person {
constructor(name) {
this.name = name;
}
get greeting() {
return `Hello ${this.name} Go rock the industry!!`
}
}
let person1 = new Person('Sara');
let person2 = new Person('Bob');
document.write(person1.name + "<br>");
document.write(person1.greeting + "<br>");
document.write(person2.name + "<br>");
document.write(person2.greeting + "<br>");
Related
I got this Javascript exercise.
I couldn't figure out how to pass the value of the pay of each person into the "comparePay" method. I'd be glad if you help me this.
Thank you in advance.
Create 3 Person objects, with the attributes "name", "occupation" and "pay", as well as the method "comparePay(person)", which compares the pay values of the object calling it and the object passed to it as argument, then printing the result:
[name of object calling the method] earns [difference] more than [other's name]
[name of object calling the method] earns [difference] less than [other's name]
[name of object calling the method] earns as much as [name]
The objects should have the following values:
Michael, JS-programmer, 5000
Lena, Python-programmer, 1500
Brad, Teacher, 800
The output should be like this.↓
First person's name: Michael
Second person's job: Python-programmer
Third person's pay: 800
Michael earns 3500 more than Lena
Brad earns 700 less than Lena
Brad earns as much as Brad
Here is what I have done so far.
function Person(name, occupation, pay) {
this.name = name;
this.occupation = occupation;
this.pay = pay;
this.comparePay = function(person) { /* compare the value of the pay */
var difference = person.pay - person.pay;
if (difference > 0) {
return person.name + " earns " + difference + " more than " + person.name;
} else if (difference === 0) {
return person.name + " earns as much as " + person.name;
} else {
return person.name + " earns " + Math.abs(difference) + " less than " + person.name;
}
};
}
person1 = new Person("Michael", "JS-programmer", 5000);
person2 = new Person("Lena", "Python-programmer", 1500);
person3 = new Person("Brad", "Teacher", 800);
and here is the prepared code, so they are not allowed to be edited.
console.log("First person's name: " + person1.name);
console.log("Second person's job: " + person2.occupation);
console.log("Third person's pay: " + person3.pay + "\n");
person1.comparePay(person2);
person3.comparePay(person2);
person3.comparePay(person3);
I think the problem comes from your comparaison (you're comparing the same object attributes). You want to compare the object passed in the function's argument with the current object.
So I guess you can try to replace
var difference = person.pay - person.pay;
with:
const difference = this.pay - person.pay;
Same for
return person.name + " earns " + difference + " more than " + person.name;
should be
return this.name + " earns " + difference + " more than " + person.name;
Otherwise it will return the same names. You can also use template literals notation
return `${this.name} earns ${difference} more than ${person.name}`;
Hope it makes sense. Also don't forget to use let or const instead of var :)
Inside the this.comparePay function you should use this to access the object properties:
this.pay, this.name, etc.
this.comparePay = function(person) {
var difference = this.pay - person.pay;
...
}
function Person(name, occupation, pay) {
this.name = name;
this.occupation = occupation;
this.pay = pay;
this.comparePay = function(person) { /* compare the value of the pay */
var difference = this.pay - person.pay;
if (difference > 0) {
return this.name + " earns " + difference + " more than " + person.name;
}
if (difference === 0) {
return this.name + " earns as much as " + person.name;
}
return this.name + " earns " + Math.abs(difference) + " less than " + person.name;
};
}
person1 = new Person("Michael", "JS-programmer", 5000);
person2 = new Person("Lena", "Python-programmer", 1500);
person3 = new Person("Brad", "Teacher", 800);
console.log(person1.name);
console.log(person1.pay);
console.log(person2.name);
console.log(person2.pay);
console.log(person3.name);
console.log(person3.pay);
console.log( person1.comparePay(person2) );
console.log( person3.comparePay(person2) );
console.log( person2.comparePay(person1) );
console.log( person3.comparePay(person3) );
Tips: You can also remove the else/if statements since you are returning inside the if statements. Paulic-crtn's advice is also important, so try to stick to let/const when declaring variables in JS.
I am trying to solve the below Javascript kata on Codewars but getting "undefined". Can please someone show me the light on what exactly is "undefined". I am struggling to understand what is missing form my code below. Cheers.
Link to challange: https://www.codewars.com/kata/training-js-number-5-basic-data-types-object
I've searched through FreeCodeCamp JS OOP and Basic tutorials / lessons to find similar problems. Searched through StackOverflow, Reddit, and Googled many websites for similar challanges.
Code below:
function animal(name, legs, color) {
this.name = name;
this.legs = legs;
this.color = color;
}
var dog = new animal("dog", 4, "white");
// similar variables set such for other animal objects.
animal.prototype.toString = function animalToString() {
var sent = "This " + this.color + " " + this.name + " has " + this.legs + " legs.";
return sent;
}
return animal.prototype.toString.call();
Expected: This white dog has 4 legs., instead got: undefined
Try this:
function animal(obj){
var newAnimal = {
name: obj.name,
legs: obj.legs,
color: obj.color
};
return "This " + newAnimal.color + " " + newAnimal.name + " has " + newAnimal.legs + " legs.";
}
The purpose of this kata I believe is to introduce you to javascript objects. The issue is thrown when you changed the inputs of the function "animal". If you look at the sample tests in the lower right corner, the inputs being fed into the function you are trying to make should accept only one parameter which is an object with properties name, legs, and color. You changed this input into three separate parameters instead of just one.
Or you could skip the assignment altogether and just access the input directly like so:
function animal(obj){
return "This " + obj.color + " " + obj.name + " has " + obj.legs + " legs.";
}
1) Based on 'instructions'
Give you a function animal, accept 1 parameter obj like this: {name:"dog",legs:4,color:"white"} and return a string like this: "This white dog has 4 legs."
function animal({name, legs, color}) {
return `The ${color} ${name} has ${legs} legs.`;
}
2) Based on what you're supposed to learn
function animal({name, legs, color}) {
this.name = name;
this.legs = legs;
this.color = color;
}
animal.prototype.toString = function animalToString() {
return `The ${this.color} ${this.name} has ${this.legs} legs.`;
}
var dog = new animal({name:"dog", legs:4, color:"white"});
dog.toString();
function animal(obj){
return `This ${obj.color} ${obj.name} has ${obj.legs} legs.`
}
You can try this
function animal(obj){
var a={name:"dog",legs:4,color:"white"}
return "This" + " " + a.color + " " +a.name + " " + "has" + " " + a.legs + " " + "legs.";
}
My knowledge of words might not be sufficient to find this by myself the explanation on the www. So please excuse me if this might be a duplicate.
I'm currently trying to figure out why we use "this" in a function constructor instead of simply returning an object?
E.g. this JSFiddle
// Using this inside function
function Student1(first,last) {
this.firstName = first;
this.lastName = last;
this.display = function(){
return this.firstName + " " + this.lastName;
};
}
const harry = new Student1("Harry", "Potter");
document.querySelector("div").innerHTML = harry.display();
document.querySelector("div").innerHTML += "<br>";
// Returning object
function Studen2(first,last){
return {
firstName: first,
lastName: last,
display(){
return this.firstName + " " + this.lastName;
}
};
}
const ron = new Student1("Ron", "Weasley");
document.querySelector("div").innerHTML += ron.display();
Anyone mind to explain or guide me to the right direction?
this works with the prototype of the instanciable function, whereas the simple object has another prototype in the chain of prototypes. It has not an own prototype of the instanciable function.
You could add a new method to the prototype and watch the difference.
// Using this inside function
function Student1(first,last) {
this.firstName = first;
this.lastName = last;
this.display = function(){
return this.firstName + " " + this.lastName;
};
}
const harry = new Student1("Harry", "Potter");
Student1.prototype.morning = function () { return 'good morning ' + this.firstName + " " + this.lastName; };
console.log(harry.morning());
// Returning object
function Studen2(first,last){
return {
firstName: first,
lastName: last,
display(){
return this.firstName + " " + this.lastName;
}
};
}
const ron = new Student1("Ron", "Weasley");
Student2.prototype.morning = function () { return 'good morning ' + this.firstName + " " + this.lastName; };
console.log(ron.morning());
Generally you will want to define the object methods on the class prototype, so that they don't have to be reinstantiated every time you create a new instance of the class, e.g.:
function Student1(first,last) {
this.firstName = first;
this.lastName = last;
}
Student1.prototype.display = function() {
return this.firstName + " " + this.lastName;
}
const harry = new Student1("Harry", "Potter");
document.querySelector("div").innerHTML = harry.display();
If you just return an (anonymous) object, it won't have a prototype and you'll have to define the function every time the construction function gets called.
Also, in your example:
harry instanceof Student1 // true
ron instanceof Student2 // false
So you can't use instanceof.
I know I can use the Invocable class to invoke methods on a class:
import javax.script.{ScriptEngine, ScriptEngineManager, Invocable}
val engine = new ScriptEngineManager().getEngineByExtension("js")
val invoker = engine.asInstanceOf[Invocable]
val person = engine.eval(s"""
new function () {
this.name = "Rick";
this.age = 28;
this.speak = function () {
return this.name + "-" + this.age;
}
};
""")
invoker.invokeMethod(person, "speak") //returns "Rick-28"
But, how do I get the name attribute of the person? I tried invoker.invokeMethod(person, "name") and I got a NoSuchMethodError.
You can cast person to a JSObject and then call person.getMember("name"). Full Java example:
ScriptEngine engine = new ScriptEngineManager()
.getEngineByExtension("js");
JSObject rick = (JSObject) engine.eval("new function () {\n" +
" this.name = \"Rick\";\n" +
" this.age = 28;\n" +
" this.speak = function () {\n" +
" return this.name + \"-\" + this.age;\n" +
" }\n" +
" };");
System.out.println(rick.getMember("name"));
Or, if the object is stored in the engine global scope like in the following javascript source:
rick = function() {
this.name= "Rick";
};
you can then call
engine.eval("rick.name");
Hai,
I am trying to understand few concepts in JavaScript. Consider the following code:
function Person(name, age)
{
this.name = name || "no name";
this.age = age || "age not specified";
this.printStr = function()
{
console.log("< " + this.name + ", " + this.age + " >");
};
}
p = new Person("pranav", 26);
p.printStr = function()
{
console.log("this works. also ...." + this.name);
};
p.printStr();
I want to call the implementation of 'printStr' in Person class from within the implementation of 'printStr' function in 'p'.
such that the output should be:
< pranav, 26 >
this works. also ....pranav
Any ideas? :)
The way your code is set up now, you can't do it. When you call Person as a constructor, the object that ends up being p gets set to this. So when you define printStr in the constructor, p gets an attribute called printStr. You then over-write it when you assign the second function.
Two options: A non-answer is to do what pablochan did - have the internal one be called oldPrintStr. Another option is to use the prototype inheritance:
function Person(name, age)
{
this.name = name || "no name";
this.age = age || "age not specified";
}
Person.prototype.printStr = function() {
console.log("< " + this.name + ", " + this.age + " >");
};
Then you can do this:
p = new Person("pranav", 26);
p.printStr = function()
{
Person.prototype.printStr.apply(this);
console.log("this works. also ...." + this.name);
};
p.printStr();
As far as I know there is no real subclassing in JS so to do this you should probably save the old function and then replace it.
p = new Person("pranav", 26);
p.oldPrintStr = p.printStr;
p.printStr = function()
{
p.oldPrintStr();
console.log("this works. also ...." + this.name);
};
p.printStr();
unless you save Person's printStr you can always create a temp Person object solely to extract printStr and call it:
p.printStr = function()
{
print("this works. also ...." + this.name);
(new Person()).printStr.apply(this);
};
but I guess you'll be better off if you make Person's original printStr accessible via prototype:
Person.prototype.printStr = function()
{
print("< " + this.name + ", " + this.age + " >");
};
then you have no need for temp object or saving old function and can do:
Person.prototype.printStr.apply(this);