In the example below I have two console.log's, and I'm getting different answers each time (despite my expecting to get the same answer).
class Dog {
constructor(name, gender) {
this.name = name;
this.gender = gender;
}
toString() {
return this.name;
}
}
let maxi = new Dog('john', 'male');
console.log(maxi) // Dog { name: 'john', gender: 'male' }
console.log(`${maxi}`); // john
In the first example, it seems like I'm logging the object's type and its properties. In the second example, however, it seems like my custom toString() method is being used to convert the object into a string.
Why the difference? And is there a place in the documentation that explains why string literals use the toString() method to convert objects into a string whereas console.log() doesn't. In addition, where does console.log() even pull this string representation of the object?
Thanks!
If you log objects in the last versions of chrome or firefox what you get logged is a reference to the object, and probably not the 'value' at the moment when you call the console.log(). but it's the value of the object at that time.
Reference : Mozilla
So what does fix this problem, convert your object into a string(your log 2), for example:
class Dog {
constructor(name, gender) {
this.name = name;
this.gender = gender;
}
toString() {
return this.name;
}
}
let maxi = new Dog('john', 'male');
console.log('Dog: ' + maxi) // Dog { name: 'john', gender: 'male' }
console.log(`${maxi}`); // {"name":"john","gender":"male"}
this works because I use the + operator instead of the , operator, so he will stick it into the string instead of making a reference to your object.
Summary
A variable does not store the value of the object, but a reference (the address in memory) for the value. So your copies that reference instead of the object.
As I think your requirement is to print object in string form so I have this solution below.
Oh I used arrow function here๐
๐
. you can use normal es5 function.
Thank you.
class Dog {
constructor(name, gender) {
this.name = name;
this.gender = gender;
}
toString() {
return JSON.stringify(this);
}
}
let maxi = new Dog('john', 'male');
console.log(`${maxi}`); // {"name":"john","gender":"male"}
I think that Console.log uses internaly a method toJSON in order to transport an object in to string. So you must write your own toJSON...
class Dog {
constructor(name, gender) {
this.name = name;
this.gender = gender;
}
toJSON() {
return this.name;
}
}
let maxi = new Dog('john', 'male');
console.log(maxi) // Dog { name: 'john', gender: 'male' }
console.log(`${maxi}`); // john
This really don't work... as Bergi tell me and he was right. I tried the code without remove the original: toString() { ... } and adding the toJSON() {...} and '>>>' like this: console.log('>>>'+maxi) and take output //>>>john. So, i thought that the toJSON() give the //>>>john, but it was the toString(). Thank you Bergi.
Related
I know the title is a bit confusing, but I have no idea to describe precisely what I mean.
I have a minimal demo below:
class A{
name: string;
age: number;
toString(){
return `
My name is: ${this.name},
My age is: ${this.age}
`
}
fromTextToData(text: string){
//Do something, regex or something?
this.name = ...;
this.age = ...;
}
}
main(){
let a = new A();
a.name = "Name 1";
a.age = 20;
let text = a.toString();
var revert = a.fromTextToData(text);
}
The best way I can think about it is using Regex expression, but if the data is large or something the structure is duplicated to its others, I think it's not really a good solution.
The second solution I can think of is using a data structure such as JSON or XML.
But I still want some suggestions from you.
That is possible, but I would first change a few things in your code:
Allow the constructor to take arguments for initialising its properties:
constructor(name, age) {
this.name = name;
this.age = age;
}
Make the reversing method a static method that returns a new instance of A instead of overwriting the properties of an existing instance. I would also just call it fromText
To better ensure that both toString and fromText rely on the same string format, define a kind of template as a static property of the A class. This template could take different forms. Here I will propose an array:
static template = ["\nMy name is: ", "\nMy age is: ", "\n"]
So the idea is that the dynamic parts get inserted between those strings. On the other hand, the reverse action can identify these strings and extract what is in between them with (.*?) as part of the regular expression.
class A {
static template = ["\nMy name is: ", "\nMy age is: ", "\n"]
constructor(name, age) {
this.name = name;
this.age = age;
}
toString(){
return [this.name, this.age]
.map((data, i) => A.template[i] + data)
.concat(A.template.slice(2))
.join("");
}
static fromText(text) {
const regex = RegExp(A.template.join("(.*?)"));
// Get the match, and extract with slice the captured groups
return new A(...text.match(regex).slice(1));
}
}
function main() {
const a = new A("Name 1", 20);
const text = a.toString();
const revert = A.fromText(text);
console.log(revert);
}
main();
Remark
If the goal is to serialise and deserialise instances, then it is better not to rely on such human-readable phrases as string representations, but use a format proven for that purpose, like JSON.
So then it would go like this:
class A {
constructor(name, age) {
this.name = name;
this.age = age;
}
toString() {
return `
My name is: ${this.name},
My age is: ${this.age}
`
}
static fromJSON(json) {
return Object.assign(Object.create(this.prototype), JSON.parse(json));
}
}
function main() {
const a = new A("Name 1", 20);
const json = JSON.stringify(a);
const revert = A.fromJSON(json);
console.log(revert);
}
main();
How can I change the way String or Number casts a class?
For example, I have the class User:
class User {
constructor(name, age) {
this._name = name;
this._age = age;
}
}
How do I convert a class object to String and get the name attribute back when I convert it to String. And if I want to convert the object of the class to Number, it returns the age attribute.
Like this:
const user = new User('Kevin', 23);
console.log(String(user)) // Kevin
console.log(Number(user)) // 23
Thanks!
Use toString and valueOf methods.
class User {
constructor(name, age) {
this._name = name;
this._age = age;
}
toString() { return this._name; }
valueOf() { return this._age; }
}
const user = new User('Kevin', 23);
console.log(String(user)) // Kevin
console.log(Number(user)) // 23
I want to know why?
It doesn't look like this reduces complexity.
String(user);
Number(user);
user.string;
user.number;
user.name;
user.age;
I am writing code for a assignment but the code i write turns out "syntax error" unexpected '' in repl.it even when getting a console.log to output expected answers the code doesn't read as true and shows code as finished
I've tried creating new variables and syncing them to this and return but the code doesn't read as true
this is what's expected "Add a method to the Person's prototype called "shoutName" that returns the person's name in all uppercase letters."
this is what returns
function Person(name) {
this.name = name;
this.shoutName = function() {
name.toUpperCase();
return.this.name.toUpperCase();
}
}
/* Do not modify code below this line */
const john = new Person('John');
console.log(john.shoutName(), '<-- should be "JOHN"');
You should remove . after return. And also you are not adding the method to prototype you are adding method to the object itself.You should add method to Person.prototype
function Person(name){
this.name = name;
}
Person.prototype.shoutName = function() {
return this.name.toUpperCase();
}
/* Do not modify code below this line */
const john = new Person('John');
console.log(john.shoutName(), '<-- should be "JOHN"');
You should have have a space between the return keyword and the value you want to return, not a dot, which causes a SyntaxError. Also, you should add the shoutName method to Person's prototype instead of each Person object that is created, for better maintainability.
function Person(name) {
this.name = name;
}
Person.prototype = {
/*add any methods you want all Person objects to have*/
shoutName: function(){
return this.name.toUpperCase();
}
};
const john = new Person('John');
console.log(john.shoutName(), '<-- should be "JOHN"');
function.apply does not register the first argument (index 0) in my array.
I have tried the rest/spread syntax, and
the code below seems to work fine:
let sayName = function (object, ...languages) {
console.log(`My name is ${this.name} and I speak ${languages.join(', ')}`);
};
let stacy = {
name: 'Stacy',
age: 34
};
let languages = ['Javascript', 'CSS', 'German','English', 'Spanish'];
sayName(stacy, ...languages);
But the code below does not work, with explicit binding function.apply:
let languages1 = ['Javascript', 'CSS', 'German','English', 'Spanish'];
sayName.apply(stacy, languages1)
The result always leaves out the 0 index from the array, i.e. "Javascript" is not included in the output.
What am I doing wrong?
Your function seems to expect an object parameter, but that is incorrect seeing how you call it with apply. When you call apply or call, the first argument to that method is used to set the this value for your function's execution context. It does not get passed as argument.
As your function references this, it is important that you set this correctly, and so the use of apply or call is the good choice.
So change:
let sayName = function (object, ...languages) {
to:
let sayName = function (...languages) {
Note that you didn't use object anyway in your function's code.
In the version where you don't call apply, but call the function directly, you do:
sayName(stacy, ...languages);
...but here the this object will not be set correctly. You should have used call to ensure that this will refer to stacy:
sayName.call(stacy, ...languages);
Check out the documentation of apply:
Syntax
function.apply(thisArg, [argsArray])
Parameters
thisArg
Optional. The value of this provided for the call to func. [...]
argsArray
Optional. An array-like object, specifying the arguments with which func should be called. [...]
Object oriented programming, a better way
Now, taking a step back you should really have defined sayName as a prototype method, and construct stacy like so:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName(...languages) {
console.log(`My name is ${this.name} and I speak ${languages.join(', ')}`);
}
}
let stacy = new Person('Stacy', 34);
let languages = ['Javascript', 'CSS', 'German','English', 'Spanish'];
stacy.sayName(...languages);
... and why not actually store the languages a person speaks as a property as well, and remove the console.log from the method, as it should be the caller who decides to where the output should be made (maybe to a file or to a HTML element):
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
this.languages = [];
}
speaks(...languages) {
this.languages = languages;
}
introduction() {
return `My name is ${this.name} and I speak ${this.languages.join(', ')}`;
}
}
let stacy = new Person('Stacy', 34);
stacy.speaks('Javascript', 'CSS', 'German','English', 'Spanish');
console.log(stacy.introduction());
I have the following Javascript snippet:`
var alien = {
kind: "alien"
};
var person = {
kind: "human"
};
var zack = Object.create(person);
alert(Object.getPrototypeOf(zack));
</script>
`
Not sure why it show zack's prototype is Object instead of person. Thanks
its also person .But person is an object.its not display with alert() try with console.log() .If you need to show with in alert use with JSON.stringify()
How can I view an object with an alert()
var alien = {
kind: "alien"
};
var person = {
kind: "human"
};
var zack = Object.create(person);
console.log(Object.getPrototypeOf(zack));
alert(JSON.stringify(Object.getPrototypeOf(zack)))
Give this a try. I cleaned up your code a bit and used the standard naming conventions of classes start with an Uppercase. Also using the console to log, alerts are so yesterday.
// Define the Alien class, always start with an uppercase
var Alien = function() {
};
// Setup it's prototype
Alien.prototype = {
kind: 'alien',
grab: function() {
return 'grabby grab';
}
}
// Define a Person class
var Person = function() {
this.kind = "human";
};
// Copy Alien prototype to Person
Person.prototype = Object.create(Alien.prototype);
// Create a new instance of of Person
var zack = new Person();
// See what's inside
console.log('Prototype function call: ' + zack.grab());
console.log('Zack is a: ' + zack.kind);
console.log('Zack is secretly a: ' + Object.getPrototypeOf(zack).kind);
console.log(Object.getPrototypeOf(zack));
The reason you see [object Object] is because when you alert Object.getPrototypeOf(zack), the object needs to convert into string to be shown in the alert. Now, default toString() method Object.prototype.toString is being called that returns the string representation of an object. If you want to really display some meaningful text in the alert, you need to implement toString method on the person object itself. Doing this would show your own text implemented in toString() function. The reason why this would happen is the way function lookup happens in javascript. First, object is looked into, then it's prototype and then further into prototype chain. Since in this case lookup would succeed at the object level itself, Object.prototype.toString function won't be called and you would see your own text in alert box.
var alien = {
kind: "alien"
};
var person = {
kind: "human"
};
person.toString = function () {
return "I am '"+this.kind+"' kind of object";
}
var zack = Object.create(person);
alert(Object.getPrototypeOf(zack));
The screen shot is showing the text returned by the Object.prototype.toString method. The method is called automatically if an object, constructed by Object, needs to be converted to text:
console.log( {} + "" ); // automatic convertion
console.log( {}.toString() ); // explicit convertion
What it is not saying is that the prototype of zack is Object. If you want more information about an object you can use JSON.stringify to create a string listing of all its non-function valued properties and their values. (JSON.stringify ignores function valued properties by design.)
You could also use equality operators to test if one object is the same as another, e.g.:
var alien = {
kind: "alien"
};
var person = {
kind: "human"
};
var zack = Object.create(person);
console.log( "zack is prototyped on person: "
+ (Object.getPrototypeOf( zack) === person)
);