How to delete a function from constructor? - javascript

How to delete a function from constructor?
If there is a function called greet in the Person constructor, how do I remove the function?
function Person(name)
{
this.name = name;
this.greet = function greet()
{
alert("Hello, " + this.name + ".");
};
}
I want the result to be:
function Person(name)
{
this.name = name;
}

delete this.greet
or
var personInstance = new Person();
delete personInstance.greet // to remove it from the instance from the outside
or
delete Person.prototype.greet // if doing prototypes and inheritance
delete is a keyword that your very rarely see but I assure you, it exists :P

You cannot change the source of a function. If you want to change that function's behaviour, you have to options:
Override the function with your own. This is easy if the function is standalone. Then you can really just define
function Person(name)
{
this.name = name;
}
after the original function was defined. But if prototypes and inheritance are involved, it can get tricky to get a reference to the original prototype (because of the way how function declarations are evaluated).
Ceate a wrapper function which creates and instance and removes the properties you don't want:
function PersonWrapper(name) {
var p = new Person(name);
delete p.greet;
return p;
}
This approach is also limited since you can only change what is accessible from the outside. In the example you provided it would be sufficient though.

Related

How does "this" keyword work in the particular way?

I'm trying to learn JavaScript, but got stuck with a problem (more with misunderstanding "this" keyword) that doesn't give me move on.
I've watched a lot of content about it and barely understood it, but still have some troubles.
I have some code:
function Person (name, age) {
this.name = name;
this.age = age;
this.changeName = function (name) {
this.name = name;
}
}
What do we use "this" here for?
As I understood we use "this" to create variable inside function constructor and give it value of our "name" parameter that we could refer to it. Am I right?
Then I have this code:
var p1 = new Person ("John", 30);
p1.changeName ("Jane");
console.log(p1.name);
As I sorted out here, we call method that overwrites our variable that we created to refer to. But it doesn't change actual parameter. So if it's right why do we use it? Doesn't it matter to have actual "name" parameter changed?
The whole code is from teaching app!
So if it's right why do we use it? Doesn't it matter to have actual "name" parameter changed?
No, there's no need to do that in this example. changeName changes the property on the object that was created by new Person.
It's true that that example code is a bit odd, because it creates the changeName function in the constructor but doesn't do the kinds of things you'd normally do when you create the function in the constructor. I'd expect that code to either be this, which puts the changeName on the prototype:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.changeName = function(name) {
this.name = name;
};
(or the class equivalent) or this:
function Person(name, age) {
this.getName = function() {
return name;
};
this.changeName = function(newName) {
name = newName;
};
this.getAge = function() {
return age;
};
}
That code does update the parameter (which has no effect at all on the code calling Person). It doesn't create name and age properties at all; instead, it just makes their values accessible via getName and getAge. There's also a function to change name (changeName); but there's no function to change age. People write code like that so that age cannot be changed from outside code created within the Person constructor.
I guess you may misunderstand which parameter you actually change, so I rewrite it like so, holp this helps.
function Person (argument_name, argument_age) {
this.name = argument_name;
this.age = argument_age;
this.changeName = function (argument_change_name) {
this.name = argument_change_name;
}
}
let p1 = new Person ("John", 30);
p1.changeName ("Jane");
console.log(p1);
The this keyword is used to create and assign values to variables in the class. It is again used to create functions, either getters or setters. So in your code this.changeName is a function that when passed a value will change the name of the person.
eg.
var a = 5; // a is an integer
var b = "Han"; //b is a string
var c = function(name){
//code here
} // then c is also a function;

Define method without using prototype

Is it possible to use the statement as shown below to define a method without the use of prototype?
Person.sayHello = function () {...}
On this example
var Person = function (firstName) {
this.firstName = firstName;
};
Person.prototype.sayHello = function() {
console.log("Hello, I'm " + this.firstName);
};
var person1 = new Person("Alice");
var person2 = new Person("Bob");
In short, no.
Person.sayHello = function () {...};
This line will add a function called "sayHello" to the Person class itself rather than to instances of the Person class. So, it can only be invoked by
Person.sayHello();
rather than by
var matt = new Person('Matt');
matt.sayHello();
// sayHello is not defined on matt
If you are familiar with Java or C#, adding a method to Person in this way is like creating a static method.
However, we can add a method to instances without adding a method to the prototype.
Method 1: Create the "sayHello" function in the constructor of Person
var Person = function (firstName) {
this.firstName = firstName;
this.sayHello = sayHello() {...};
};
This method has the disadvantage that a new function is created for every instance of Person. That is,
var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello != matt.sayHello;
Thus, this method can be hard on memory. However, it does allow for encapsulation (e.g. private state) via closures. In the following sample, it is impossible to modify the "count" variable outside of the Person class without calling the "sayHello" function.
var Person = function (firstName) {
this.firstName = firstName;
this.sayHello = sayHello() {
count++;
console.log("Hello has been said " + count + "times".
};
var count = 0;
};
Method 2: Create the "sayHello" function outside the constructor of Person and assign it within the constructor of Person
var Person = function (firstName) {
this.firstName = firstName;
this.sayHello = sayHello;
};
function sayHello() {...}
This method has the advantage of lower memory usage; there is only one instance of the sayHello function, and it is shared across instances of Person. That is,
var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello == matt.sayHello;
This makes it similar to the prototype method. However, the assignment of the function to each instance still consumes more memory than the prototype method where the function is only assigned to the prototype object.
However, like the prototype method, this method does not allow for private state. All state must be accessed through public state exposed via the this keyword.
Update: Clarification of the difference in memory usage between method 1 and method 2.
Method 1 is like this:
var function1 = function() { console.log('Hello'); };
var function2 = function() { console.log('Hello'); };
The functions have the same behavior, but are not equal. JavaScript doesn't know they are functionally similar, so it creates two functions in memory to represent them.
Method 2 is like this:
var sayHello = function() { console.log('Hello'); };
var function1 = sayHello;
var function2 = sayHello;
Now function1 and function2 are actually the same function because they both simply hold a reference to sayHello.
Update: Example usage of a module pattern to avoid adding "sayHello" to the global scope in method 2.
This module defines the Person class in a module defined by an anonymous closure (a self executing function) and exports it to the global scope. Because "sayHello" is defined in the closure of the module and is not exported, it is not added to the global scope.
var Person = (function () {
function Person(firstName) {
this.firstName = firstName;
this.sayHello = sayHello;
};
function sayHello() {...}
return Person;
}());
Yes, you can. If you come from traditional OO background, it might help to think about this as effectively behaving like a public static property on a class.
As jsdeveloper said in the above comment. Functions are just objects that can be executed. You can add properties to them just like any other object. This technique is actually used in practice for patterns like memoization or currying.
In your case sayHello can accessed anywhere the Person function can be accessed. It's not really related to inheritance/prototype since it doesn't have to do with resolving properties by traversing the prototype chain, but it is another way to make data accessible.
I'm sure it varies based on the developer, but I often put pure functions which don't reference this as static methods as you have done since they are easier to test and make the intention clear to other developers
It would be weird, but if you really need to do it that way, you can assign the function to its own prototype once, then add all of the functions to the main function.
var Person = function (firstName) {
this.firstName = firstName;
};
Person.prototype = Person;
Person.sayHello = function() {
console.log("Hello, I'm " + this.firstName);
};
Yes you can but the sayhello function will not be able to access any of the object properties (ie this.myvar) and you can only call it like a static method:
Person.sayhello()
(and not mypersonobject.sayhello).
When you extend the prototype, the sayhello function is available to all Person objects created using the 'new' keyword in the usual fashion.
https://jsfiddle.net/jsheridan390/kL7arrqs/

javascript: explanation needed for this piece of code

Who can explain me this code (alert "Hi! My name is Mark" appears):
function Person(name) {
var self = this;
this.name = name;
function person(){
alert("Hi! My name is "+self.name);
}
return {person:person};
}
new Person("Mark").person();
and why I don't see alert if return {person:person}; is removed? What person:person is here?
Also, why this.name (not self.name) is undefined in function person(){}?
The main problem is that you should not return {person:person}, but you should not specify a return or "return this;".
new Person("Mark") will create an instance of Person, but the function Person returns the {person:person}. Inside {person:person} the right one(value) is the method.
var x = new Person("Mark") will return {person: function person(){alert("Hi...")}.
x.person() will show the alert.
Niels' answer is correct, and to answer the rest of your question, this.name doesn't work inside the child function because name belongs to the parent function so you have to declare an instance of that parent scope (in your case self) to be able to access the properties of the parent.
This code is very tricky:
function Person(name) {
//'P' makes us think about this function as a constructor
var self = this;
// Closure, when the person function is executed
//"this" is not a Person, is another object, but "self" will be accesible
// by the function person
this.name = name;
// this is an internal function, it does not exist out of Person
function person(){
alert("Hi! My name is "+self.name);
}
return {person:person};
//This should not be here if the Person function were a proper constructor,
//it returns an object which only attribute is the function person
}
new Person("Mark").person();
// as Person returns an object (not a Person object) with the person attribute,
// you can call that attribute
The equivalent but clearer code to this one is:
var p={
person: function () {
var self={name: "Mark"};
(function(){
alert("Hi! My name is "+ self.name);
})();
}
};
p.person();

Most optimized way to create JS Object

I'm looking for the most optimized way to have an object in JS; since JS allows you to do something in multiple ways I want to know which is considered to be "best practice".
A conceptual use of the object would be this:
var John = new Person('John');
var Foo = new Person('Foo');
console.log(John.getName()); //Return 'John'
console.log(Foo.getName()); //Return 'Foo'
console.log(John.name); //undefined
console.log(Foo.name); //undefined
I have some examples here:
Example #1:
var Person = function (name) {
this.getName = function () { return name; }
}
Here I actually have no properties; "name" cannot be changed or be read by public and getName method can be accessed public and invoke with local name variable. This actually meets my needs.
Example #2:
function Person (name) {
this.getName = function () { return name; }
}
This has same behaviour as example #1. I'm just not sure about the difference between var method = function () {}; and function method() {}; from a functional and performance perspective.
Example #3:
var Person = function (name) {
this.name = name;
Person.prototype.getName = function () { return this.name; }
}
Here I have name property which can be read/write by public and I also have a prototype getName method that can be accessed public.
Example #4:
var Person = function (name) {
this.name = name;
if (!Person._prototyped) {
Person.prototype.getName = function () { return this.name; }
Person._prototyped = true;
}
}
Here I have what I had in example #3 with the difference that I make sure that prototype methods are set only once and only when required.
So the end question is, which of those you will suggest me to follow or if any of them then which way is the best practice?
For what you want, the best way is probably this:
/**
* #constructor
*/
function Person(name) {
this.getName = function() {
return name;
};
}
Why is this? Well, first of all, encapsulation. If possible, you generally want to put the function in the prototype, like so:
/**
* #constructor
*/
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
};
However! In this case, it appears you don't want Person.name to be accessible. For that reason, you need to use closures.
As for this method:
var Person = function (name) {
this.name = name;
Person.prototype.getName = function () { return this.name; }
}
That's not good. You publicly expose this.name, so it offers no advantage over the previous prototype method, but you continually overwrite Person.prototype.getName with the same function. There's no point in doing that; this will be the appropriate object every time. What's more, Person.prototype.getName won't be accessible until the first Person object is instantiated so there's not much point in making it "public" in the first place. Your fourth example is basically identical, with more cruft making it harder to understand, but it still has all the disadvantages.
So, in this case, go with the first version; when possible, though, set methods on prototype so they can be called outside of an instance.
Finally, I would recommend using:
function Person() {
}
over
var Person = function() {
}
because 1) The second example is missing a semicolon, 2) the var implies that the constructor is variable which it should not be, and 3) I don't believe JDoc allows #constructor to be applied to it, causing a warning in Closure Compiler at least1.
1 Okay, not so important. But still...
In example 3 and 4 it should be:
var Person = function (name) {
this.name = name;
};
Person.prototype.getName = function () { return this.name; }
And:
var Person = function (name) {
this.name = name;
};
if (!Person._prototyped) {
Person.prototype.getName = function () { return this.name; }
Person._prototyped = true;
}
As you don't need to mess with the prototype each time you call the constructor.
Not sure which is fastest (as they are all valid for your purposes), which is what your asking, but I wouldn't worry as this seems like micro-optimizing. If you must know then you can use a site like http://jsperf.com/
The fastest way I can imagine would be :
function Person(name) {
this.getName = function() {
return name;
};
}
As minitech said. The reason is as follows:
Each time the js engine has to go "up" the prototype chain it takes away a fraction of a ms (or fraction of a sec on IE :) ), and as declaring variables can take up time (also negligible) you avoid doing that too. Hope that helps
Works well on node.js. AFAIK, arguments are mutable. Closures will remember values. Hence this will work. I guess this solves it all.
var Person = function(Name) {
this.getName = function(){return Name;}
this.setName = function(newName) { Name = newName; }
},
me = new Person('John');
console.log(me.getName());
me.setName('Peter');
console.log(me.getName());

How to find the function name of namespaced constructors in javascript?

For example, compare these two:
function Person(name) {
this.name = name;
}
var john = new Person('John');
console.log(john.constructor);
// outputs: Person(name)
var MyJSLib = {
Person : function (name) {
this.name = name;
}
}
var john2 = new MyJSLib.Person('John');
console.log(john2.constructor);
// outputs: function()
The first form is useful for debugging at runtime. The 2nd form requires some extra steps to figure out what kind of object you have.
I know that I could write a descriptive toString function or call the toSource method on the constructor to get some more information, but I want the simplest way possible.
Is there a way to do this? Suggestions?
Well that happens because you are using an anonymous function.
You can specify names of anonymous functions (yes, it sounds odd), you could:
var MyJSLib = {
Person : function Person (name) {
this.name = name;
}
}
var john2 = new MyJSLib.Person('John');
console.log(john2.constructor);
Anonymous functions can be named but those names are only visible
within the functions themselves, and since you use the new operator, the constructor property will be set, and you will be able to see the name.
You could also compare the constructor reference using or not a name for the function:
console.log(john2.constructor === MyJSLib.Person); // true
If you want to check whether an object is instance of a specific class then simply use "instanceof" keyword to check that. If you explicitly want a name for the constructor(which I really cannot see a point) you may try the code below
var MyJSLib = {
Person : function Person(name) {
this.name = name;
}
}
what you want is the name of the holder in the namespace so.
function getName(namespace, obj) {
for name in namespace:
if (namespace[name] == obj) return name;
}
console.log(getNameOf(MyJSLib, john2.constructor));

Categories