differences between defining functions/methods in JS? - javascript

Here are 3 ways to address the key-value pair of objects constructed using constructor. What are the differences among these 3 ways in every describable aspects? (I would even like to enquiry about basic differences between function & method in terms of their functionality, usage, etc.)
function Person(name,age) {
this.name = name;
this.age = age;
}
var bob = new Person("Bob Smith", 30);
var me = new Person('Madhav Devkota', 55);
//===================================================
//A. Simple function
printPerson= function (p) {
console.log(p.name);
};
printPerson(bob); printPerson(me);
//===================================================
//B. Method I
printPerson = function(){
console.log(this.name) ;
};
bob.printPerson = printPerson; me.printPerson = printPerson;
bob.printPerson(); me.printPerson();
//=================================================
//C. Method II
this.printPerson = function() {
console.log(this.name);
};
bob.printPerson(); me.printPerson();

I would also add
// 0. No function
console.log(bob.name);
console.log(me.name);
It is the most basic way. You are doing something with you object properties directly.
A. Simple function
You are giving your code a name to improve semantics. Now you are describing what your code is intended to do.
You can access more properties and combine to create complex result without code repetition.
printPerson = function (p) {
console.log(p.name + ' is aged ' + p.age)
}
instead of No function
console.log(bob.name + ' is aged ' + bob.age);
console.log(me.name ' is aged ' + me.age);
B. Method I
Now your function is also a property of your object. Unlike simple function which works in scope where it is declared, your method it attached to your object and you can pass it around along with it. When invoked 'this' references the object from which method is invoked.
You can also do a 'nonsense' method like this:
printPerson = function(p){
console.log(p.name) ;
};
bob.printPerson = printPerson; me.printPerson = printPerson;
bob.printPerson(bob); me.printPerson(me);
C. Method II
This one is not quite right. It doesn't make sense in given context as 'this' is at that moment referencing Window object. At then end you are actually calling 'Method I' methods again.
Correct way to use it is in constructor function:
function Person(name,age) {
this.name = name;
this.age = age;
this.printPerson = function() {
console.log(this.name);
};
}
Now your objects have .printPerson() method as soon as they are created.
I could elaborate more if you wish but it's important to notice that function vs method difference is not too relevant at this level of code complexity. When your code gets more complex code organization becomes important. For 'next level' you should get more familiar with Javascript scoping and object inheritance.

Related

Can I bind a constructor's prototype methods to constructed instances while keeping concerns separated?

Say I have an object constructor and a prototype method, like:
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function(){
console.log('my name' + this.name);
};
Elsewhere in my code, I've defined an instance of human:
let jeff = new Human('jeff');
and lastly I want to pass jeff.sayName as a callback to some other function, like (for a particularly trivial example)
function callFunction(callback) {
callback();
}
callFunction(jeff.sayName);
When I call callFunction(jeff.sayName) above, the context needs to be bound to jeff itself, like
callFunction(jeff.sayName.bind(jeff)). But this is clunky, and I'd rather not have to worry about this sort of logic every time I use this method as a callback.
An alternative would be to replace Human.prototype.sayName with something like
Human.prototype.createSayName = function(context){
return function() {
console.log(context.name);
};
};
and then define the function with
jeff.sayName = jeff.createSayName(jeff)
but this is a bit awkward, and I'd like to keep jeff agnostic to the methods it inherits from Human.prototype.
So ideally I'd like to handle this logic on Human.prototype itself, something like
Human.prototype.sayName.bind(WhateverObjectHoldsThisMethod)
but I'm not aware javascript has a way of doing this.
TL;DR I would like a way of binding an object's prototype method to whatever object inherits it, without having to do so every time I pass that method as an argument or every time I define a new object. Sorry if this makes little sense. Thanks!
Due to the way lexical environments, scope resolution, prototypal inheritance, and environment records work in JavaScript, what you're asking for is not possible without modifying the function which calls the callback function.
However, you could—instead of passing the Human#sayName reference as the call back—use an arrow function that in turn calls the Human#sayName reference you wish to call.
It's not perfect, but it's simple, clean, and readable.
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function(){
console.log('my name' + this.name);
};
let jeff = new Human('jeff');
function callFunction(callback) {
callback();
}
callFunction(_ => jeff.sayName());
For a better understanding of those fancy words I referenced earlier, and how they work in JavaScript, I would recommend reading section 8.1 of the ECMAScript 2017 Language Specification. Subsection 8.1.1.3 has the specific information you're looking for, but the rest of the section up to that point is necessary to understand that subsection.
Basically, when you pass Human#sayName to callFunction, you're passing the reference to the original sayName function, so you might as well be doing this: (pardon the pun)
function callFunction(callback) {
callback();
}
callFunction(function(){
console.log('my name' + this.name);
});
The content of the function is not evaluated until it is executed, which means by the time it is executed, the value of this has already changed. To add to the debacle, the original function has no knowledge of which instance you requested it through. It never actually exists on the jeff object. It exists in the prototype of the the function object, and when you perform the object property look up, the JavaScript engine searches the prototype chain to find that function.
You very well could get the behavior you're asking for, but not under the constraints you have laid out. For example, if the function does not have to exist on the prototype chain, and can instead exist on the instance (keep in mind that this creates a new function object for each instance, so it will increase cost), you could define the function in the constructor, then store a reference to the correct this using an identifier that will not be overwritten:
function Human(name) {
const _this = this;
this.name = name;
this.sayName = function(){
console.log('my name' + _this.name);
};
}
let jeff = new Human('jeff');
function callFunction(callback) {
const _this = { name: 'hello' }; // does not affect output
callback();
callback.call(_this); // does not affect output
}
callFunction(jeff.sayName);
This would be a safer option, because you know that _this will always refer to the object you're expecting it to refer to within the context of the constructor, all function objects defined within that function object will inherit the identifiers of their parent scope, and those identifiers will not be affected by the calling context.
Or, you could go one step further, and not rely on the value of this at all:
function Human(name) {
const sayName = function(){
console.log('my name' + name);
};
Object.assign(this, { name, sayName });
}
let jeff = new Human('jeff');
function callFunction(callback) {
const name = 'hello'; // does not affect output
callback();
callback.call({ name: 'world' }); // does not affect output
}
callFunction(jeff.sayName);
This has the advantages of:
Being easier to read,
Less code,
Allowing you explicit about the properties and methods being exposed through the object, and
Never having to worry about what the value of this will be.
I suppose you may want to achieve this
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function() {
console.log('my name' + this.name);
};
let jeff = new Human('jeff');
function callFunction(callback) {
callback();
}
callFunction(function() {
jeff.sayName()
});
another guess, a prototype bound to an instance, it works but has anti-patten
function Human(name) {
this.name = name;
}
const jeff = new Human('jeff');
Human.prototype.sayName = function() {
console.log('my name' + jeff.name);
};
function callFunction(callback) {
callback();
}
callFunction(jeff.sayName);
another guess, relection
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function() {
console.log('my name' + this.name);
};
Human.prototype.reflectName = function(item) {
this.sayName = () => item.sayName()
};
const jeff = new Human('jeff');
const tod = new Human('tod');
tod.reflectName(jeff)
tod.sayName()
Expanding on TinyGiant answer, you can use an arrow function, but if you combine it with a getter, you can define it as a method of the prototype and not bother with defining your callback as a arrow function, which may be more flexible depending on your needs. Like this:
function Human(name) {
this.name = name;
}
Object.defineProperty(Human.prototype, "sayName", {
get: function() {
return () => {
console.log("my name is", this.name);
}
}
});
function callfunction(callback) {
callback();
}
let jeff = new Human('jeff');
callfunction(jeff.sayName);
// just to show it works even as a regular function
jeff.sayName();
// in fact it overrides every context you bind
jeff.sayName.bind(window)()

how does "new" work with classes in javascript?

How does the new work differently in the 2 examples below? I see that the 2nd example is replacing the annoymous funciton with a variable, but in the second one, the function/class "Person" is actually being called. Does it make any difference if it's being called or not? I tried it without the calling and it still worked. So that led me to believe that new is actually calling the function and setting up this to be assigned to the instance variable.
var person = new function() {
this.setName = function(name) {
this.name = name;
}
this.sayHi = function() {
return "Hi, my name is " + this.name;
}
}
person.setName("Rafael");
console.log(person.sayHi()); // Hi, my name is Rafael
var Person = function() {
this.setName = function(name) {
this.name = name;
}
this.sayHi = function() {
return "Hi, my name is " + this.name;
}
}
var personTwo = new Person()
personTwo.setName("Rafael");
console.log(personTwo.sayHi()); // Hi, my name is Rafael
There would be almost no difference between these two examples, if it was a simple function like this:
(function() { console.log("IIFE"); })();
// or
var f = function() { console.log("Function"); };
f();
You just store your function in a variable, and then call it.
However, it makes a little difference, since it is related to JS OOP mechanisms. In the first case you get Object instance, and in the second you get Person instance. This makes difference in OOP sense.
var person = new function() { };
console.log("Is instance of: " + person.constructor.name);
console.log("There is no way to check instanceof in this case");
var Person = function() { };
var person = new Person();
console.log("Is instance of: " + person.constructor.name);
console.log(person instanceof Person);
In general, new and classes are supposed to be used as in the second case in order to enable the full functionality of JS OOP. There is absolutely no sense or/and advantage in using anonymous class constructor.
Whether or not it is assigned into a variable: does not matter. It is completely parallel to this example:
var x = 1;
console.log(x);
and
console.log(1);
Whether it needs to be called or not: A function with the new operator is always being called, but with new, parentheses are optional when no parameters are passed: new Person() is equivalent to new Person, but new Person("Joe") cannot be done differently.
In the second example, you are passing to the new operator the exact same function. You simply are using a reference (logically stored in a variable) instead of writing literal function just in place.
So, your second example is the same as:
var personTwo = new (function() {
[...]
})()
[...]
Which, in fact, is much the same as the first one:
var person = new (function() {
[...]
})
[...]
NOTE that the parentheses surrounding the function are absolutely optional in this case. You could be placed there seven if you like: (((((((function(){[...]}))))))).
The point here is that when you say «in the second one, the function/class "Person" is actually being called» you are WRONG there: That function, which acts as a constructor isn't being called by you. You are simply passing it as a parameter (the constructor function) of the new operator which is, in fact, who is actually calling the constructor with the rest of parameters you provided, if any.
See new syntax documentation:
new constructor[([arguments])]
The constructor is the function you pass to the new operator and the parameters are specified between parentheses. But they are fully optional (including the parentheses itself).
This is why new constructor; without parentheses works.
To be clear: What you thought happens (but not) would be written as:
var person = new ((function(){...})()) ();
...or, more verbosely:
var person = new (
(function(){ // Constructor builder.
[...]
return function(){...}; // Actual constructor.
})() // Constructor builder call
//v-- Parentheses to force builder to be called.
) (); // <-- Parameters (if any) passed to the constructor.

Javascript fundamental clarification needed

I know little bit C# and now I have started working with JavaScript and I got some problems in understanding the fundamentals.
Here is my code sample:
function BaseFunc(x, y) {
this.X = x;
this.Y = y;
}
function DerivedFunc(x, y, z) {
this.Z = z;
BaseFunc.call(this, x, y);
}
DerivedFunc.prototype = new BaseFunc;
function Test() {
var d = DerivedFunc(1, 2, 3);
var b = new BaseFunc(4, 5);
d.sayHello();
b.sayHello();
}
DerivedFunc.prototype.sayHello = function () {
alert("Result is: " + (this.X + this.Y + this.Z));
}
In the above code I am trying to make an inheritance.
Everything looks good until I reach the line BaseFunc.call(this, x, y); this line is supposed to call base function but what is the use of this in this context.
Is it just to satisfy the signature of method call, how does it work ?
Second question is, in javascript we can add anything dynamically,
In my case I am adding a sayHello() property and assigning it with an anonymous function.
like DerivedFunc.prototype.sayHello, am I adding a property/method to BaseFunc or DerivedFunc, as it is added to prototype it should be added to BaseFunc as I understand it. But when I execute the above code I get error that sayHello is not defined.
Can someone please clarify me about what is going wrong, thanks?
Everything looks good until I reach the line BaseFunc.call(this, x, y); this line is supposed to call base function but what is the use of this in this context.
It's there so that within the call to BaseFunc, this has the same value it has in the call to DerivedFunc, so that the lines this.X = x; and such in BaseFunc are assigning to the correct instance. (Calling a function setting a specific value for this is what the .call and .apply methods of functions do.)
But when I execute the above code I get error that sayHello is not defined.
If it's d.sayHello where you're having the trouble, it's because you've missed out the new operator on the line d = DerivedFunc(1, 2, 3);. Since DerivedFunc, when just called as a function and not via new, doesn't have any return value, d will be undefined.
Note that the way you're doing inheritance, though common, has issues. The main issue is here:
DerivedFunc.prototype = new BaseFunc;
You're trying to use a function designed to create instances, and which accepts arguments, in order to create the prototype instance that DerivedFunc will assign to things. What then is BaseFunc supposed to do about the arguments that are missing? Then later, you call it again (from DerivedFunc) to initialize the instance. BaseFunc is doing double-duty.
Here's how you correct that, first the long-winded version:
function x() { }
x.prototype = BaseFunc.prototype;
DerivedFunc.prototype = new x;
DerivedFunc.prototype.constructor = DerivedFunc;
Or if you can rely on ES5's Object.create:
DerivedFunc.prototype = Object.create(BaseFunc.prototype);
DerivedFunc.prototype.constructor = DerivedFunc;
Now we're not calling BaseFunc to create the prototype, but we are still getting its prototype object as the underlying prototype of DerivedFunc's prototype object. We no longer have the problem of what to do with BaseFunc's arguments, and BaseFunc is only called in the way it's designed to be called: To initialize individual instances, not prototypes.
Naturally, rather than writing that for every time we want to have derived constructors, you'd have a helper script for it.
If you're interested in JavaScript inheritance hierarchies, you may want to look at my short Lineage script — not necessarily to use, but to understand how these things work. The page showing how to do things without the script and comparing to doing them with the script may be particularly useful.
Hi please go through the following. I hope it will give you some idea about inheritence and call()
<script type="text/javascript">
//inheritence
function parent() {
this.add = function (a, b) {
return a + b;
}
this.subtract = function (a, b) {
return a - b;
}
}
function child() {
this.display = function () {
alert(this.add(11, 23));
}
}
child.prototype = new parent(); //child extends parent.... inheritence
child.prototype.constructor = child; //resetting constructor property
var obj = new child();
obj.display();
/*
.call() and .apply()
They allow our objects to borrow methods from other objects and invoke them as their own
*/
var person = {
name: 'Kundan',
display: function(name) {
alert(this.name + ' welcomes ' + name);
}
};
person.display('Dipa'); //Kundan welcomes Dipa
var person1 = { name: 'Java Master' };
person.display.call(person1, 'Sachin'); //Java Master welcomes Sachin
//here person1 object is passed in the call function
//if we are using call inside a function and want to pass the same function object then this is passed in call function
/*
We can pass more parameters as follows
person.display.call(person1, 'a', 'b', 'c');
The method apply() works the same way as call() but with the difference that all parameters you want to pass to the method of the other object are passed as an array.
*/
person.display.apply(person1, ['a', 'b', 'c']);
</script>

javascript functions and objects using keyword 'this' does not work

my question here is about functions and objects in javascript. I have three questions that stems from one to other. In the below example, I try to access the value of 'a' in test, but I get undefined. but I create a new object of test, then I am able to access the 'a' value and change it.
//create a function called test
var test=function() {
this.a=2
this.b=3 };
test.a//undefined
//create a object called test1 using 'new'
test1 = new test();
test1.a//2
//change the value of a in test1
test1.a=4
test1 //Object { a=4, b=3}
while trying to find why this happens, I came across this javascript functions are objects? and another question popped out of this.
The accepted solution for that SO question is below
var addn = function func(a) {
return func.n + a;
};
addn['n'] = 3;
addn(3);
I changed the 'func.n' to 'this' and it no longer works
var addn=function func(a) {
return this.n+a;
};
addn['n']=3;
addn(3); //NaN
making anonymous function with 'this' also did not help
//anonymous function
var addn=function(a) {
return this.n+a;
};
addn['n']=3;
addn(3); //NaN
why using 'this' did not work?
one final question, what is the difference in using keyword 'new' and 'createObject'. Douglas Crokford suggests using 'CreateObject' in his book, but I fail to understand why. Thanks all for your comments
1. Functions are constructors for new objects
When you call new FuncName, the function acts as a constructor, and the value of this inside points to the object being constructed (not the function itself). When you remove new, this becomes undefined, falling back to the global object (unless you're in strict mode).
2. Functions are also objects
Every function is an instance of Function, so the functions themselves are objects and can have have their own properties. Those properties cannot be accessed with this.propName inside the function body, only with funcName.propName. That's because this inside a function is never the function object itself (unless you forced it to be, with bind, call, or apply).
I hope both topics above help you understand how functions work. As for your final question: Crockford's createObject is a different way to implement inheritance, doing basically what Object.create does in ES5-compliant browsers. It allows an object to inherit straight from another object, without requiring you to manually create a new constructor, set its prototype property (which is an example of a property on a function object), and create an instance with new. Crockford prefers that, and said he stopped using new in favor of this approach.
In response to the questions you asked in chat, here is an attempt to explain what functions are and what they do, with examples.
Functions can be just... functions
You call them, they do something:
function alertThis(what) {
alert(what)
}
alertThis("alerting something");
You can also pass them values, and have them return values
function timesTwo(num) {
return num * 2;
}
timesTwo(2); // 4
They can be passed and return anything, including objects...
function createPerson(firstName, lastName) {
return {
firstName : firstName,
lastName : lastName
}
}
var john = createPerson('John', 'Doe');
john.lastName; // "Doe"
...and other functions:
function timesN(n) {
return function(num) {
return n * num;
}
}
var timesThree = timesN(3);
timesThree(5); // 15
Functions are objects
Functions can be passed around and returned like any ordinary object. That's because they are objects. Like any object, they can have properties:
function countCalls() {
countCalls.timesCalled++;
}
countCalls.timesCalled = 0;
countCalls();
countCalls();
countCalls.timesCalled; // 2
One very important default property of functions is prototype. It's a special property, and we'll see why.
Functions can act as constructors for new objects
Functions can behave like class constructors do in regular OO languages. When called with new, they create a new object of a certain "class". This new object is called this inside the function, and is automatically returned:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
var john = new Person('John', 'Doe');
john.firstName; // "John"
john instanceof Person; // true
... unless you deliberately return something else:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
var fakePerson = {
firstName : firstName,
lastName : lastName
};
return fakePerson;
}
var notPerson = new Person('John', 'Doe');
notPerson.firstName; // "John"
notPerson instanceof Person; // false
// Note: the object called 'this' inside the function is created, but
// after the function is called there is no outside reference to it.
Objects created by constructors know who created them, and can see their prototype property
Back to a real person:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// Add something to the Person prototype
Person.prototype.sayHi = function() {
return "hi, I'm " + this.firstName;
}
var john = new Person('John', 'Doe');
john.sayHi(); // "Hi, I'm John"
john.constructor; // Person
The object john can sayHi() because it has access to everything inside its constructor's prototype property. But it cannot see other properties of Person directly (only through their own constructor property):
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
Person.timesCalled++;
// There is no 'this.timesCalled', only Person.timesCalled
}
Person.timesCalled = 0;
var john = new Person('John', 'Doe');
john.timesCalled; // undefined - john cannot be called, Person can
john.constructor.timesCalled; // 1
1.
addn['n'] = 3; //Means you add static property n to the function(object) addn.
so addn.n also work.
2
this.n means property n of the instance.
this.n === undefined so it returns NaN.
3 var addn=function func(a) means you give a second name to func.
var addn=function(a) is better format in most case.
4 createObject is not a native javaScript code. 'New' is.

Do functions attached to the prototype property not have closure

I am trying to figure out how I can add methods to a constructor after I have created it.
In my code below, I cannot use Person's prototype property to add a new public method which has access to Person's vars. (Do the functions attached to the prototype property not close over the vars in the main function).
Unlike the first way, the second way works - Person 2. seems like these are called privileged methods -http://www.crockford.com/javascript/private.html.
function Person(name, age){}
Person.prototype.details = function(){
return "name: "+name+", age: "+age;
};
function Person2(name, age){
this.details = function(){
return "name: "+name+", age: "+age;};
}
var per1 = new Person("jim", 22);
var per2 = new Person2("jack", 28);
per1.details();
//=> ReferenceError: age is not defined
per2.details();
//=> "name: jack, age: 28"
No, they do not have closure over the constructor functions vars. They are in a different scope.
// This function is in one scope.
function Person(name, age) {
}
// This statement is in the parent scope, which
// doesn't have access to child scopes.
Person.prototype.details = function(){
return "name: "+name+", age: "+age;
};
That's the way that "public" functions work in JavaScript. You could make details a privileged function by defining it within the constructor:
function Person(name, age) {
this.details = function() {
return "name: "+name+", age: "+age;
};
}
Of course, that means that each instance of Person gets it's own copy of the details function.
You could also, as #Chuck suggests, make name and age public members, in which you would have access to them in a prototype function:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.details = function(){
return "name: " + this.name + ", age: " + this.age;
};
No. Typically you would either use the second approach, or set this._name = name; in the constructor and reference it that way in the other method.
Of course not, the function was declared in a scope, different to the scope where the arguments/variables were declared, so JS wouldn't know which variables you're on about. Suppose you had a second closure, or better (well, worse actually) yet: a global variable called name. Which one would JS pick?
Here's an example for you:
function MyObject(name)
{
var localVar = 'foobar';
this.evilMethod = (function(localVar)
{
return function()
{
console.log('localVar = '+localVar);//=== name
};
})(name);
this.badMethod = function()
{
console.log('localVar = '+ localVar);// === 'foobar'
};
}
var name = 'Global Name';
var anotherClosure = (function(name)
{
var localVar = name.toLowerCase();
return function()
{
console.log(name);
console.log(localVar);
}
})('Bobby');
MyObject.prototype.closureVars = function()
{
console.log(name);//Global name
console.log(localVar);//undefined
};
Now first off: this is terrible code, but you get the point: you can have hundreds of variables with the same name, which one JS has to use, might not always be clear.
Giving prototypes access to instance closure variables has other implications, too: you could, for instance change their values, which defeats the point of having a closure in the first place. But the biggest problem by a country mile would be: multiple instances! If you create a constructor, odds are you're going to instantiate more than 1 object with it. How would that work, if they all share the same prototype?
Just assign the arguments/variables you want to access in the prototype to a property, like FishBasketGordo's example does

Categories

Resources