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

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).

Related

this keyword vs object name when adding method to existing object

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

Why is this the output for javascript?

var name = 'bob';
var someObject = {
name: 'james',
someProperty: {
name: 'sam',
getName: function(){
return this.name;
}
}
}
var testing = someObject.someProperty.getName;
testing();
Is the reason this block of code returns 'bob' because we are just ultimately calling this.name on a global object's name, which is 'bob' or is there a better way to think about this problem? Thanks!
The value of this is determined by how a function is called.
testing() is invoked as window.testing() hence this refers to window and as var name is under the global(scope of window), "bob" is returned.
You can use [.call'(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call) of ES5 to specify this context to get "sam".
The call() method calls a function with a given this value
Use .bind() to have a specified this-reference context in function-body, The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
var name = 'bob';
var someObject = {
name: 'james',
someProperty: {
name: 'sam',
getName: function() {
return this.name;
}
}
}
var testing = someObject.someProperty.getName;
console.log(testing()); //bob
console.log(testing.call(someObject)); //james
console.log(testing.call(someObject.someProperty)); //sam
console.log('------OR--------')
var testing = someObject.someProperty.getName.bind(someObject);
console.log(testing());
var testing = someObject.someProperty.getName.bind(someObject.someProperty);
console.log(testing());
Running the above code in Chrome Dev Console I got the following output:
Input:
var testing = someObject.someProperty.getName;
testing();
Output:
"bob"
But then I changed as:
Input:
var testing = someObject.someProperty.getName();
testing;
Output:
"sam"
Well, in the first scenario, "testing" becomes a function object which will the return the value of global "name" variable. "testing" has nothing to do with "someObject" in this case. Which is similar to:
// global scope
var testing = function() {
return this.name;
}
In the second scenario, "testing" is simply the returned value of "someObject.someProperty.getName()".
When you call testing, the function is being invoked without an object context and the global context is used for the this pointer. this.name on the global context is 'bob' and hence the result. Calling someObject.someProperty.name() would return 'sam'. If you want it to return 'james' you need to call it like this:
someObject.someProperty.getName.call(someObject);
or:
var testing = someObject.someProperty.getName.bind(someObject);
testing();
Just to add on, if you want to use a function to get sam, you can wrap the function call in another function:
var testing = someObject.someProperty.getName;
testing(); // "bob"
function getSam(){
return someObject.someProperty.getName();
}
getSam(); // "sam"
I believe you are partly mixing up this simple object literal with object constuctors. The object literal someObject does not automatically engage this - its pretty much the same as a bunch of variables.
var name = 'bob';
var someObject = {}
someObject.name = 'james'
someObject.someProperty = {};
someObject.someProperty.name = 'sam';
someObject.someProperty.getName = function(){
return this.name; // global context
}
You can approximate instancing, _and thus engage this to in javascript in a few ways:
Using Object.create
Passing the object literal someObject to Object.create() will create a new context for this as you might expect:
var name = 'bob';
var someObject = {
name: 'james',
someProperty: {
name: 'sam',
getName: function(){
return this.name;
}
}
}
var aNewContext = Object.create(someObject);
aNewContext.someProperty.getName();
// "sam"
Using Function constructors
When you use the keyword new with a function, it also creates a new object and assigns it to this. Functions added to the prototype can be called as methods, will also reference this:
function SomePropertyConstructor() {
this.name = 'sam';
}
SomePropertyConstructor.prototype.getName = function(){
return this.name;
}
var name = 'bob';
var someObject = {
name: 'james',
someProperty: new SomePropertyConstructor()
}
someObject.someProperty.getName();
// "sam"
Note - if you call the function on its own, you will need to control the context using bind:
var unbound = someObject.someProperty.getName;
[ unbound(), unbound.bind(someObject.someProperty)()]
//["bob", "sam"]
var name = 'bob';
var someObject = {
name: 'james',
someProperty: {
name: 'sam',
getName: function() {
console.log(this);
return this.name;
}
}
}
var testing = someObject.someProperty.getName;
testing()
Window {external: Object, chrome: Object, customElements: undefined, originalOutline: undefined, someObject: Object…}
When I tried that, noticed how the result of my (this) was printed, and it refers to the global "this". This isn't what we want.
If I wanted to print "sam", I would do this to call it with a way to redefine what "this" means.
testing.bind(someObject.someProperty)(). // returns "sam"
In addition you can also do this:
var name = 'bob';
var someObject = {
name: 'james',
someProperty: {
name: 'sam',
getName: function() {
return this.name;
}.bind(someObject.someProperty)
}
}
var testing = someObject.someProperty.getName;
This will return "sam" when you call it, regardless of the "this" context.
Another way of doing this is to keep your original code, but instead of setting
var testing = someObject.someProperty.getName;
instead change it to:
var testing = someObject.someProperty.getName();
This way now the object refers to the getName() function using the context of your someProperty.

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

class variable in Javascript

How do I declare class variables in Javascript.
function Person(){
fname = "thisfname"; //What needs to be put here
}
alert(Person.fname) //It should alert "thisFrame"
I don't want to use this approach.
function Person(){
}
Person.fname = "thisfname";
alert(Person.fname) //alerts "thisframe"
JavaScript does not have classes like others have said. Inheritance is resolved through prototyping which in essence does nothing more than create non-deletable property references on a newly created object. JavaScript also has alternatives for simple data objects, namely object literals.
The variation of a 'Class' in JavaScript should be defined as such:
// I use function statements over variable declaration
// when a constructor is involved.
function Person(name) {
this.name = name;
}
// All instances of Person create reference methods to it's prototype.
// These references are not deletable (but they can be overwritten).
Person.prototype = {
speak: function(){
alert(this.name + ' says: "Hello world!"');
}
};
var Mary = new Person('Mary');
Mary.speak(); // alerts 'Mary says: "Hello world!"'
The this reference always points to the owner of the function. If you call Person without the new operator, the owner will be the global scope (window). If you do not use this reference to assign properties to your instance, then the properties will simply be declared as variables. If you do not use the var statement, then those declarations will create global variables which are bad!
more about this
Using the this reference in a constructor function is exceedingly important if you want to add properties to the current instance. Without using this, you only create a variable (which is not the same as a property) and as mentioned, if you don't use the var statement either, you create global variables.
function Person(){
name = 'Mary'
}
var p = new Person();
alert(p.name); // undefined, did not use 'this' to assign it to the instance.
alert(name); // 'Mary', boo, it created a global variable!
Use this!
function Person(){
this.name = 'Mary'
}
var p = new Person();
alert(p.name); // 'Mary', yay!
alert(name); // undefined, yay!
Note, anything assigned to an instance through the function constructor CANNOT BE INHERITED unless you assign it to the prototype and overwrite it again in the function constructor to make it an owned property.
When you create a new instance of through a function doubling as a constructor, actually the following happens.
pseudo code:
copy Person.prototype as person
invoke Person function on person
return person
Actually, this is what happens in every classical language when you create an instance of a class. But the main difference in JavaScript is that it's not encapsulated inside a nice Class statement. Originally JavaScript didn't even have function constructors but was added on later because SUN demanded they wanted JavaScript to be more like Java.
Object literals
The alternative for function constructors for objects that carry only intrinsic data and no methods are object literals.
var Mary = {
firstName: 'Mary',
lastName: 'Littlelamb'
};
Which is the prefered way of declaring intrinsic objects rather then:
// do not ever do this!
var Mary = new Object();
Mary.firstName = 'Mary';
Mary.lastName = 'Littlelamb';
With object literals in your skill set, you can create a factory pattern for intrinsic data objects using the module pattern (which is usually for singletons).
var createPerson = function(firstName, lastName){
return {
firstName: firstName,
lastName: lastName
}
}
var Mary = createPerson('Mary', 'Littlelamb');
This achieves some comfortable encapsulation, but can only be used for intrinsic data objects.
Another thing you can do with Object literals and JavaScript is delegation, which should be preferred.
var personMethods = {
speak: function(){
alert(this.firstName + ' says: "Hello world!"');
}
};
var Mary = {
firstName: "Mary",
lastName: "Littlelamb"
};
var Peter = {
firstName: "Peter",
lastName: "Crieswolf"
};
personMethods.speak.apply(Mary); // alerts 'Mary says: "Hello world!"'
personMethods.speak.apply(Peter); // alerts 'Peter says: "Hello world!"'
Why should this be preferred? Because it keeps your objects minute and readable, even prototypical references take up memory and when using inheritance and 'subclassing' you end up with child instances that have lots of unused method references. Delegation is always better.
The way you mentioned is how to define class variables, the other way (inside function Person) is to define instance properties.
function Person(name){
this.name = name;
}
Person.specie = "Human";
alert(Person.specie) //alerts "Human", a class variable.
var john = new Person('John');
alert(john.name); //alerts "John", an object property.
It is important to understand that there is no such thing as classes in JavaScript. There are some frameworks out there that simulate a classical inheritance pattern, but technically it all boils down to constructor functions and prototypes.
So, you may want to do something like
PersonProto = { // the "class", or prototype
fname: "thisfname"
};
function Person() { // the constructor function
this.instanceVar = 'foo';
}
Now, connect the constructor to the prototype:
Person.prototype = PersonProto;
And, voilà:
var a = new Person();
alert(a.fname);
function Person(){
this.fname = null;
this.lname = null;
this.set_fname = set_fname;
this.set_lname = set_lname;
this.get_name = get_name;
}
/* Another way
function Person(fname, lname){
this.fname = fname;
this.lname = lname;
this.get_name = get_name;
}*/
function set_fname(fname){
this.fname = fname;
}
function set_lname(y){
this.lname = lname;
}
function get_name(){
with (this) {
return fname + ' ' + lname;
}
}
person_obj = new Person();
person_obj.set_fname('Foo');
person_obj.set_lname('Bar');
// person_obj = new Person('Foo', 'Bar');
person_obj = get_name(); // returns "Foo Bar"
Can't think of better example.
3 ways to define a variables to JavaScript class:
1)To define properties created using function(), you use the 'this' keyword
function Apple (type) {
this.type = type;
this.color = "red";
}
To instantiate an object of the Apple class, set some properties you can do the following:
var apple = new Apple('macintosh');
apple.color = "reddish";
2) Using Literal Notation
var apple = {
type: "macintosh",
color: "red"
}
In this case you don't need to (and cannot) create an instance of the class, it already exists.
apple.color = "reddish";
3) Singleton using a function
var apple = new function() {
this.type = "macintosh";
this.color = "red";
}
So you see that this is very similar to 1 discussed above, but the way to use the object is exactly like in 2.
apple.color = "reddish";
You can also try this approach:
function name() {
this.name;
this.lastname;
}
name.prototype.firstName = function(name) {
this.name = name;
alert(this.name);
}
var x = new name();
x.firstName("Kartikeya");

Categories

Resources