this keyword vs object name when adding method to existing object - javascript

function Foo(name, age){
this.name = name;
this.age = age;
this.announce = function(){
alert(this.name + " is " + this.age + " years old");
};
}
var myFoo = new Foo("John", 42);
Lets say I want to add a method to this particular instance of Foo (not to the others).
Should I use this keyword to modify the age property
myFoo.becomeYounger = function(){
this.age--;
};
or should I refer to the object by its name since it already exists?
myFoo.becomeYounger = function(){
myFoo.age--;
};
Which one is better/faster or is there any difference whatsoever?

They both work, but there are some risks about using the object name, look at this:
let user = {
name: "John",
age: 30,
sayHi() {
alert( user.name ); // leads to an error
}
};
let admin = user;
user = null; // overwrite to make things obvious
admin.sayHi(); // Whoops! inside sayHi(), the old name is used! error!
By using this, the code would worked correctly, just take care about this kind of scenarios.
Also if you like to do reusable code, using this fits better:
let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
// use the same functions in two objects
user.f = sayHi;
admin.f = sayHi;
// these calls have different this
// "this" inside the function is the object "before the dot"
user.f(); // John (this == user)
admin.f(); // Admin (this == admin)
admin['f'](); // Admin (dot or square brackets access the method – doesn't matter)
To learn more, here:
https://javascript.info/object-methods

Related

What is the use of declaring variable inside constructor

I was studying class based structure in Javascript
To say the least, I created a simple class
class something {
constructor() {
var name = "somexyz"
this.age = 13
}
somefunc () {
console.log(this.name)//Undefined
console.log(name) //blank space
console.log(this.age) //13
}
}
And then call it using
let foo = new something()
foo.somefunc()
Which consoles.log (mentioned in comments of above code)
1. undefined
2. empty space
3. 13
or take a constructor function
function something () {
this.age = 11
let age = 13
this.getAge = function () {
return this.age
}
}
Here,
let somethingNew = new something()
Will return age as 11
Now, my question is what exactly is the purpose of having variable in constructors then?
The emphasis should be on "simple class" - the notion of a local variable seems pointless but it's actually very useful.
Simple example - when you reuse a variable repeatedly
class transport
{
constructor ()
{
const someString = "IUseThisAgainAndAgain";
this.type = 'someType';
this.name = 'someName';
this.serial = someString + "SOMETHING";
this.model = someString + "something thing";
this.example = someString + "another string concat";
}
}
As you can see we use someString alot. And you will see constructor method that are huge and having a variable for a repeated instance will allow better readability of code and allow you to easily modify the instance in one place.
You can use variables to set a default value also for checking purposes or mathematical calculations.
For example:
class something {
constructor(age) {
var default_age = "13";
if(age > 13){
this.age = age;
}else{
this.age = default_age;
}
}
myage() {
console.log("I am "+this.age+" years old.")
}
}
var newobj = new something(15);
newobj.myage();
var newobj2 = new something(8);
newobj2.myage();
vars in constructor are only defined in the scope of the constructor
In this case "" is a string that is present in the global scope. Not finding name in the current scope of the method execution, it is finded moved up to the window.name. Try to change name with something else (ex: name2) and You'll get an error.
For logging "somexyz" see the snippet below
Of course, the local variables in the constructor should be useful for the logic of the constructor itself
class something {
constructor() {
var name = "somexyz"
var name2 = "somexyz"
this.age = 13
}
somefunc () {
console.log(this.name)//undefined
console.log(name) //window.name
console.log(window.name) //window.name
console.log(this.__proto__.constructor.name) //"something"
console.log(this.age) //13
}
}
let foo = new something()
foo.somefunc()

Adding a method to an object that is inside of a function in js

Hi this is from a challenge I was working on. Is there any way i can add the introduce method to the personStore object without using the keyword this. Any insight is greatly appreciated.
Using Object.create
Challenge 1/3
Inside personStore object, create a property greet where the value is a function that logs "hello".
Challenge 2/3
Create a function personFromPersonStore that takes as input a name and an age. > When called, the function will create person objects using the Object.create method on the personStore object.
Challenge 3/3
Without editing the code you've already written, add an introduce method to the personStore object that logs "Hi, my name is [name]".
Side Curiosity
As a side note, was curious if there was a way to add the introduce method to the person object that sits inside of the personFromPersonStore function.
my solution:
var personStore = {
// add code here
greet: function (){
console.log('Hello');
}
};
function personFromPersonStore(name, age) {
var person = Object.create(personStore);
person.name = name;
person.age = age;
person.greet = personStore.greet;
return person;
};
personStore.introduce = function () {
console.log('Hi, my name is ' + this.name)
}
//Challenge 3 Tester
sandra.introduce(); // -> Logs 'Hi, my name is Sandra
You can, but using this is a lot simpler.
This code passes the name property as an argument, but as the property is already accessible to the introduce function as an internal property via this, it is a bit wasteful.
var personStore = {
// add code here
greet: function (){
console.log('Hello');
}
};
function personFromPersonStore(name, age) {
var person = Object.create(personStore);
person.name = name;
person.age = age;
person.greet = personStore.greet;
return person;
};
personStore.introduce = function (nm) {
console.log('Hi, my name is ' + nm)
}
person1=personFromPersonStore('Fred',21);
person1.introduce(person1.name);
You can write it like this:
personFromPersonStore("whatevername","whateverage").name
instead of this.

How to assign a bound object function to another object property?

I tried to bind a function from an object to some variable without external calling bind():
var man = {
age: "22",
getAge: function(){
return "My age is "+this.age;
},
test: function(){
return this.getAge.bind(this);
}
}
This works:
var a = man.test();
a();
// "My age is 22"
But when I try to change some things in my code:
var man = {
age: "22",
getAge: function(){
return "My age is "+this.age;
},
test: function(){
return this.getAge.bind(this);
}()//there it's, that do not do "var a = man.test()", but "var a = man.test"
}
JavaScript gives me an Error:
Uncaught TypeError: Cannot read property 'bind' of undefined(…)
What am I doing wrong?
this in your second version is not referring to what you think it is, it's referring to the window and so does not have the property available...
NB: Adding the () to the end calls the anonymous function you created
In your example this is referring to the context the Object literal is written in, not the Object literal.
You can't actually refer to yourself in an Object literal's construction time because even it's identifier hasn't been properly set yet. Instead, separate it into two steps
// 1, set up with a literal
var man = {
age: "22",
getAge: function () {
return "My age is " + this.age;
}
}
// 2, set up things needing references to the object we just made
man.test = man.getAge.bind(man);
By your specific example it looks like you may repeat this pattern many times, are you sure that it wouldn't be better to use a Constructor? This also means you can use inheritance and prototyping
For example, you could have Man set up as inheriting from Human, and also create a Woman later with shared code
// Common category
function Human(age) {
this.age = age;
this.test = this.getAge.bind(this);
}
Human.prototype = Object.create(null);
Human.prototype.getAge = function () {
return 'My age is ' + this.age;
};
// specific category
function Man(age) {
Human.call(this, age);
}
Man.prototype = Object.create(Human.prototype);
Man.prototype.gender = function () {
return 'I am male.';
};
// then
var man = new Man('22'); // as you used a string age
var a = man.test;
a(); // "My age is 22"
Then later
// another specific category
function Woman(age) {
Human.call(this, age);
}
Woman.prototype = Object.create(Human.prototype);
Woman.prototype.gender = function () {
return 'I am female.';
};
// then usage
var woman = new Woman('22'); // as you used a string age
woman.getAge(); // "22", because getAge was common to humans

How do I call a public function from within a private function in the JavaScript Module Pattern

How do I call a public function from within a private function in the JavaScript Module Pattern?
For example, in the following code,
var myModule = (function() {
var private1 = function(){
// How to call public1() here?
// this.public1() won't work
}
return {
public1: function(){ /* do something */}
}
})();
This question has been asked twice before, with a different accepted answer for each.
Save a reference to the return object before returning it, and then use that reference to access the public method. See answer.
Save a reference to the public method in the closure, and use that to access the public method. See answer.
While these solutions work, they are unsatisfactory from an OOP point of view. To illustrate what I mean, let's take a concrete implementation of a snowman with each of these solutions and compare them with a simple object literal.
Snowman 1: Save reference to return object
var snowman1 = (function(){
var _sayHello = function(){
console.log("Hello, my name is " + public.name());
};
var public = {
name: function(){ return "Olaf"},
greet: function(){
_sayHello();
}
};
return public;
})()
Snowman 2: Save reference to public function
var snowman2 = (function(){
var _sayHello = function(){
console.log("Hello, my name is " + name());
};
var name = function(){ return "Olaf"};
var public = {
name: name,
greet: function(){
_sayHello();
}
};
return public;
})()
Snowman 3: object literal
var snowman3 = {
name: function(){ return "Olaf"},
greet: function(){
console.log("Hello, my name is " + this.name());
}
}
We can see that the three are identical in functionality and have the exact same public methods.
If we run a test of simple overriding, however
var snowman = // snowman1, snowman2, or snowman3
snowman.name = function(){ return "Frosty";}
snowman.greet(); // Expecting "Hello, my name is Frosty"
// but snowman2 says "Hello, my name is Olaf"
we see that #2 fails.
If we run a test of prototype overriding,
var snowman = {};
snowman.__proto__ = // snowman1, snowman2, or snowman3
snowman.name = function(){ return "Frosty";}
snowman.greet(); // Expecting "Hello, my name is Frosty"
// but #1 and #2 both reply "Hello, my name is Olaf"
we see that both #1 and #2 fail.
This is a really ugly situation. Just because I've chosen to refactor my code in one way or another, the user of the returned object has to look carefully at how I've implemented everything to figure out if he/she can override my object's methods and expect it to work! While opinions differ here, my own opinion is that the correct override behavior is that of the simple object literal.
So, this is the real question:
Is there a way to call a public method from a private one so that the resulting object acts like an object literal with respect to override behavior?
You can use this to get the object your privileged method greet was called on.
Then, you can pass that value to your private method _sayHello, e.g. using call, apply, or as an argument:
var snowman4 = (function() {
var _sayHello = function() {
console.log("Hello, my name is " + this.name);
};
return {
name: "Olaf",
greet: function() {
_sayHello.call(this);
}
};
})();
Now you can do
var snowman = Object.create(snowman4);
snowman.greet(); // "Hello, my name is Olaf"
snowman.name = "Frosty";
snowman.greet(); // "Hello, my name is Frosty"
And also
snowman4.greet(); // "Hello, my name is Olaf"
snowman4.name = "Frosty";
snowman4.greet(); // "Hello, my name is Frosty"
With module pattern, you hide all the innates of an object in local variables/functions, and usually employ those in your public functions. Each time a new object is created with a module pattern, a new set of exposed functions - with their own scoped state - is created as well.
With prototype pattern, you have the same set of methods available for all objects of some type. What changes for these methods is this object - in other words, that's their state. But this is never hidden.
Needless to say, it's tough to mix those. One possible way is extracting the methods used by privates into a prototype of the module's resulting object with Object.create. For example:
var guardian = function() {
var proto = {
greet: function () {
console.log('I am ' + this.name());
},
name: function() {
return 'Groot';
}
};
var public = Object.create(proto);
public.argue = function() {
privateGreeting();
};
var privateGreeting = public.greet.bind(public);
return public;
};
var guardian1 = guardian();
guardian1.argue(); // I am Groot
var guardian2 = guardian();
guardian2.name = function() {
return 'Rocket';
};
guardian2.argue(); // I am Rocket
var guardian3 = guardian();
guardian3.__proto__.name = function() {
return 'Star-Lord';
};
guardian3.argue(); // I am Star-Lord

In JavaScript: Syntax difference between function & method definition within a class

The Object class has both methods and functions meaning they both are accessed through Object.nameOfMethodOrFunction(). The following question What is the difference between a method and a function explains the difference between a method and and a function, but it doesn't explain how to create them within an object. For example, the code below defines the method sayHi. But how do you define a function inside the same object?
var johnDoe =
{
fName : 'John',
lName: 'Doe',
sayHi: function()
{
return 'Hi There';
}
};
The following defines two classes, ClassA and ClassB, with equal functionality but different in nature:
function ClassA(name){
this.name = name;
// Defines method ClassA.say in a particular instance of ClassA
this.say = function(){
return "Hi, I am " + this.name;
}
}
function ClassB(name){
this.name = name;
}
// Defines method ClassB.say in the prototype of ClassB
ClassB.prototype.say = function(){
return "Hi, I am " + this.name;
}
As shown below, they doesn't differ much in usage, and they are both "methods".
var a = new ClassA("Alex");
alert(a.say());
var b = new ClassB("John");
alert(b.say());
So now what you mean for "function", according to the msdn link that you gave as a comment, seems that "function" is just a "static method" like in C# or Java?
// So here is a "static method", or "function"?
ClassA.createWithRandomName = function(){
return new ClassA("RandomName"); // Obviously not random, but just pretend it is.
}
var a2 = ClassA.createWithRandomName(); // Calling a "function"?
alert(a2.say()); // OK here we are still calling a method.
So this is what you have in your question:
var johnDoe =
{
fName : 'John',
lName: 'Doe',
sayHi: function()
{
return 'Hi There';
}
};
OK, this is an Object, but obviously not a class.
Quoting Aaron with "A method is on an object. A function is independent of an object".
Logically a method is useless without a "this" defined.
Consider this example:
var johnDoe =
{
fName: 'John',
lName: 'Doe',
sayHi: function () {
return 'Hi There, my name is ' + this.fName;
}
};
function sayHi2() {
return 'Hi There, my last name is ' + this.lName;
}
//Will print Hi there, my first name is John
alert(johnDoe.sayHi());
//An undefined will be seen since there is no defined "this" in SayHi2.
alert(sayHi2());
//Call it properly now, using the oject johnDoe for the "this"
//Will print Hi there, my last name is Doe.
alert(sayHi2.call(johnDoe));
var johnDoe = {
fName: 'John',
lName: 'Doe',
sayHi: function(){
function message(){ return 'Hi there'; }
return message();
}
};
That's about as good as you're going to get with the object declaration method of creating a 'class' in JavaScript. Just keep in mind that function is only valid within sayHi's scope.
However, if you use a function as a class structure, you have a little more flexibility:
var johnDoe = function(){
this.publicFunction = function(){
};
var privateFunction = function(){
};
};
var jd = new johnDoe();
jd.publicFunction(); // accessible
jd.privateFunction(); // inaccessible
(though both are really considered methods since they have access to the object's scope within).

Categories

Resources