Let say a I have an object:
var person= {
firstName:"Renzo",
getFirstName:function(){
console.log(this);// is the person object
return this.firstName;
},
address:{
number:function(){
console.log(this);// is the number function
//return person.getFirstName(); // it is working
return this.firstName;// not working
}
}
};
console.log(person.getFirstName());
console.log(person.address.number());
I know that "this" in the getFirstName method will reference to the person object, but "this" in the number method will not reference to the person object will reference to the number function.., I can access the getFirstName method from number function referencing to the person object, that will solve the problem but...
Question:
Is there way to reference the person object from the number method? without using the person variable... is there some special keyword like "this", to access the person method??
Another way you could do this is during the call itself:
var person = {
firstName: 'Renzo',
getFirstName() {
return this.firstName;
},
address: {
number: function() {
return this.firstName;
}
}
}
// then call it
person.address.number.call(person); // 'Renzo'
You can use ES6 classes and arrow functions to be able to achieve this.
class Person {
constructor() {
this.firstName = "Renzo";
this.address = {
getNumber: () => this.firstName
}
}
getFirstName() {
return this.firstName;
}
}
var person = new Person();
console.log(person.address.getNumber());
Here is a working fiddle - https://jsfiddle.net/sgsvenkatesh/qtg1s2f2/1/
If you are looking for a reserved keyword for accessing the grand parent, there is no such thing. You will need to tweak your code to be able to do it.
You could construct the address, so that it has access to its parent object:
function Person(n){
this.firstName=n;
this.address=new Adress(this);
}
Person.prototype= {
firstName:"Renzo",
getFirstName:function(){
console.log(this);// is the person object
return this.firstName;
}
};
function Address(p){
this.parent=p;
}
Address.prototype={
number:function(){
console.log(this);// is the number
console.log(this.parent);//the parent
return this.parent.getFirstName(); // it is working
}
};
Usecase:
console.log((new Person("Me")).address.number());
You can use it like this
var person= {
firstName:"Renzo",
getFirstName:function(){
return this.firstName;
},
address:{
number:function(){
return person.firstName;
}
}
};
console.log(person.address.number());
Related
I explore the deep end of JavaScript.
Well, let's say I have a constructor function like this. Yes, I know this is a weird way of creating a constructor function, but ...
function Animal(name){
return { name };
}
And I wanna add a prototype property like walk(), but it doesn't work here. I know it looks stupid, but...
Animal.prototype.walk = function () {
console.log(`${this.name} is walking ...`);
}
QUESTION: Is there any way that I can add this walk property as a prototype property?
If you have to explicitly return an object that isn't this in the constructor, then:
Create the prototype object outside, then use Object.create inside the constructor:
const animalProto = {
walk() {
console.log(`${this.name} is walking ...`);
}
};
function Animal(name){
return Object.assign(Object.create(animalProto), { name });
}
const a = new Animal('foo');
a.walk();
But this is strange, can you do it the normal way and assign to a property of this instead?
function Animal(name){
this.name = name;
}
Animal.prototype.walk = function () {
console.log(`${this.name} is walking ...`);
}
const a = new Animal('foo');
a.walk();
or if you want to avoid listing name twice
function Animal(name){
Object.assign(this, { name });
}
Animal.prototype.walk = function () {
console.log(`${this.name} is walking ...`);
}
const a = new Animal('foo');
a.walk();
I am not sure about differences between object literal and constructor function.
function user() {
this.name="john"
this.getName=function (){
return this.name;
};
}
var johnUser=new user();
console.log(johnUser.getName()); // Will console john
What if I want to call getName without creating any objects something like in Java static method/function?
If I can add
user.sayName=function() {
console.log("Hey there");
}
console.log(user.sayName()); //will console Hey there.
How I can access constructor function properties?
The answer is You can't.
You should have read about how context of function works in JS.
When You are using new operator, empty object is being passed as context, that's why You can assign properties of this (which is reference to function context)
When You are calling a function without new operator, context of Your function is eiter global object (window) or undefined. You can print this in function to see what context You have ATM.
What You (probably) want is to create an prototype
Object literal
var user = {
name: "John",
getName: function(){
return this.name;
}
};
Alternatively, this approach won't define an object.
function sayName()
{
return "just a string";
}
function user() {
this.name = 'john';
}
user.prototype.getName = function(){ return this.name; }
var johnUser = new user();
console.log( johnUser.getName() ) // john
console.log( user.prototype.getName()); // undefined
user.prototype.getName = function(){ return 'just a string' }
console.log( johnUser.getName() ) // just a string
console.log( user.prototype.getName());// just a string
user.prototype.getName = function(){ return this.name || 'just a string'; }
console.log( johnUser.getName() ) // john
console.log( user.prototype.getName());// just a string
I'm trying do define a simple class called Mail using the new ECMAScript 2015 JavaScript classes as defined here.
I came up with this constructor and tried the following getter:
class Mail {
constructor(sender, date, subject, text) {
this.sender = sender;
this.date = date;
this.subject = subject;
this.text = text;
}
get sender() {
return this.sender;
}
}
But when I tried to use that method, it didn't work.
var mail = new Mail("#mail.com", Date.now(), "Testing", "Text");
console.log(mail.sender());
Returned:
TypeError: mail.sender is not a function
So, my doubt is:
Is it necessary to define getters and setters like in Java or can I simply access field like mail.sender (or so)?
If it is necessary, how to properly define getters and setters to each of class instance variables?
getter and setter are basically hooks to capture get- and set- actions for properties of an object. They are functions, but they seem (to the code that uses this Object) like a property.
var mail = new Mail("#mail.com", Date.now(), "Testing", "Text");
console.log(mail.sender); //no brackets
and if you add a setter, main.sender = "#foo.bar".
And I'm wondering that your code didn't get stuck in an infinite recursion, since your getter called itself.
class Mail {
constructor(sender, date, subject, text) {
this._sender = sender;
this._date = date;
this._subject = subject;
this._text = text;
}
//this IS `this.sender`!
//it should not `return this.sender`, since this would call this getter again,
//and you get stuck in an infinite recursion.
get sender() {
return this._sender;
}
//and a possible setter, that handles
//instance.sender = whatever;
set sender(value) {
this._sender = value;
}
}
Edit:
Does this mean that I can just ignore get and set methods because I can directly access object field?
you don't need getter or setter to make any property public in JS, simply defineing this property makes it public available. JS works the other way around, you have to take additional efforts to make things private (see closures). In JS everything is by default public.
But you can use getter (and setter) to fulfil additional tasks, like:
class Person{
constructor(firstName, lastName){
//regular public properties
this.firstName = firstName;
this.lastName = lastName;
}
//a composed value, that you can access like a property
get fullName(){
return this.firstName + " " + this.lastName;
}
//you could also add a setter like this
set fullName(value){
[this.firstName, this.lastName] = value.split(/\s+/g);
}
}
var john = new Person("John", "Doe");
console.log(john.fullName);
To use getters and setters, you just need to use and set the property. in your case: mail.sender. This will call the getter if you are using the value, or the setter if you are overriding the current value.
class Mail {
constructor(sender) {
this._sender = sender;
}
get sender() {
return "Sender: " + this._sender;
}
set sender(val) {
this._sender = val.toLowerCase();
}
}
const m = new Mail("TEST");
console.log(m.sender); // => "Sender: TEST"
m.sender = "TEST";
console.log(m.sender); // => "Sender: test"
Note that I used _sender to store the value to prevent a Maximum call stack size exceeded error.
You can use the property like any other property, and it will automatically call the getter or setter.
If what you were looking for is encapsulation, you could design your classes like so:
const Mail = (function() {
let sender; // this is "private"
return {
title: "public", // This is public
get sender() {
return sender;
},
// ...
};
});
In this case, you would then create new Mail objects like so:
const mail = Mail();
You could return a function in the Mail function in order to be able to instantiate new objects with the new keyword.
You actually did more than you need to. You don't need getters as you specified.
Try this:
class Mail {
constructor(sender, date, subject, text) {
this.sender = sender;
this.date = date;
this.subject = subject;
this.text = text;
}
}
var mail = new Mail("#mail.com", Date.now(), "Testing", "Text");
console.log(mail.sender);
JavaScript has no concept of classes.
The class keyword is just syntactic sugar.
What a class do is, it generates a constructor function for you.
const Person = class { // or `class Person`
constructor(name) {
this.name = name;
}
say(msg) {
return `${this.name} says: "${msg}".`;
}
}
That's exactly the same, what you will achieve with the following code.
const Person = function(name) {
this.name = name;
};
Person.prototype = {
say(msg) {
return `${this.name} says: "${msg}".`;
}
};
If you need private variables, you have to work with closures.
const Person = class { // or `class Person`
constructor(name) {
this.getName = () => name;
this.setName = (newName) => {
name = newName;
}
}
say(msg) {
return `${this.getName()} says: "${msg}".`;
}
}
let p = new Person('me');
console.log(p.name); // undefined
console.log(p.getName()); // 'me'
p.setName('he');
console.log(p.getName()); // 'he'
console.log(p.say('something')); // 'he says: "something".'
I advice you to not use class and to avoid new.
If you need an object, you simply can use factory functions:
const Person = function(name) {
let person = Object.create(Person.prototype);
person.name = name;
return person;
};
Person.prototype = {
say(msg) {
return `${this.name} says: "${msg}".`;
}
};
I have heard about the prototype method to apply one function or variable to several objects. But it does not work for me somehow. I created many objects kind of like this:
var item = {
a: {
aa: "lalala",
ab: 1,
something: 3
},
b: {
ba: "jfjb",
bb: 2,
something: 4
}
}
But when I know use the prototype method
item.prototype.bob = 2;
it does not work and shows me the error
Cannot set property 'bob' of undefined"
Same for a method
item.prototype.bob = function() {
100 - this.something;
this.something++;
}
Do you know what I do wrong or is there a different method to apply the same variable or function to many objects?
You confuse classes with object instances. You just have an anonymous object. item is the instance, not the class.
In the snippet below, a class is declared (Item, with capital i), an instance is created (item), and the prototype of the class is modified. You will see then that you can set a property on the prototype and read it though the instance, if you like.
var Item = function() {
a = {
aa: "lalala",
ab: 1,
something: 3
};
b = {
ba: "jfjb",
bb: 2,
something: 4
};
}
var item = new Item();
Item.prototype.bob = 'x';
alert(item.bob);
The classic way is
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.greet = function() {
console.log(this.firstName + " says hello");
}
var pete = new Person("Peter", "Pan");
pete.greet();
Note that the prototype attribute is on the constructor (the function object we invoke with new to construct the object), not the constructed object itself.
In ECMAScript 6, you'll be able to write this in a more compact way:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
greet() {
console.log(this.firstName + " says hello");
}
}
new Person("Peter", "Pan").greet();
The prototype property is called on the class name and not on the object name. So, if item is an object of class MyClass then you should write:
MyClass.prototype.bob = 2;
You can find more information on the links below:
http://www.w3schools.com/js/tryit.asp?filename=tryjs_object_prototype5
http://www.w3schools.com/js/js_object_prototypes.aspenter link description here
Here your item is an object by itself,it does not has any constructor, so you cannot define or set on prototype.Your code throws error
To fix this, it has to be something like the below
function item(a,b){
this.a=a;
this.b=b;
}
function a(aa,ab,something){
this.aa=aa;
this.ab=ab;
this.something=something
}
item.prototype.bob=2;
item.prototype.method1 = function() {
100 - this.something;
this.something++;
}
Hope this helps
I have a JavaScript class like this:
Dog = (function() {
var name;
function setName(_name) {
name = _name;
}
return {
setName: setName,
name: name
};
})();
When I run:
Dog.setName('Hero');
Dog.name is always undefined.
I am certainly missing something about JS scoping, but what?
You are returning an object where name property has a value of name at that point in time (which is undefined). The name property of the returned object is not somehow dynamically updated when the name variable inside the IIFE is updated.
There are many ways to handle what you appear to be wanting to do. Here's one:
Dog = (function() {
var name;
function setName(_name) {
name = _name;
}
return Object.defineProperties({}, {
setName: { value: setName },
name: { get: function() { return name; } }
});
})();
This keeps name as a private variable, which can only be set via setName, but provides a getter property for obtaining its value.
The alternative proposed in another answer is equivalent, just a different way of writing it:
return {
setName: function(n) { name = n; },
get name: function() { return name; }
};
Minor point, but in this particular context you don't need parentheses around your IIFE:
Dog = function() { }();
will work fine.
This happens because you assume that setting name in the object retains a reference to the original name variable. Instead, you want to assign it to the current object (which, you might as well ignore the private variable altogether).
Dog = {
name: '',
setName: function(n) {
this.name = n;
}
};
However, if you want to keep name private then you create a getter for it instead.
var Dog = (function() {
var name;
return {
setName: function(n) {
name = n;
},
get name: function() {
return name;
}
};
})();
The easy way to fix this is:
Dog = (function() {
var dog = {
setName: setName,
name: name
};
function setName(_name) {
dog.name = _name;
}
return dog;
}
In your code, you were setting the wrong name variable.
var name;
function setName(_name) {
name = _name;
}
In this function, setName is setting the internal variable name and not the property name. In JavaScript, strings are immutable, so when you change it, it creates a new string, and doesn't update the existing one.
This might be a better pattern for you. You're using the very old ES3 style constructor.
(function(exports) {
function Dog(name) {
this.name = name;
}
Dog.prototype.speak = function() {
return "woof";
};
// other functions ...
exports.Dog = Dog;
})(window);
var d = new Dog('Hero');
console.log(d.name); // "Hero"
You might want to look into ES6 classes too
class Dog {
constructor(name) {
this.name = name;
}
}
let d = new Dog('Hero');
console.log(d.name); // "Hero"
Sounds like you want to make a constructor... Check this sample:
function Dog(prop) {
this.name = prop.name;
this.color = prop.color;
}
var myDog = new Dog({
name:'Sam',
color: 'brown'
});
alert()
console.log('my dog\'s name is: '+myDog.name);
console.log('my dog\'s color is: '+myDog.color);
you can try it here: http://jsfiddle.net/leojavier/ahs16jos/
I hope this helps man...
Use the 'this' keyword.
Dog = (function() {
var name;
function setName(_name) {
this.name = _name;
}
return {
setName: setName,
name: name
};
})();
Dog.setName('Hero');
alert(Dog.name);