how does "new" work with classes in javascript? - 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.

Related

differences between defining functions/methods in JS?

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.

Add self executing init method to constructor function?

Let’s say I have a constructor function which I do not have access to. Into this constructor function I want to inject a self executing init method which gets executed whenever a new instance gets created from this constructor.
For example: let’s say there is a Cat constructor, but I unfortunatly do not have access to it:
function Cat() {
// ...code which I do not have access to
// ...maybe it comes from an external file or something?
}
And I can now of course do this to create new cats:
var coolCat = new Cat();
All is well and I have my new cat instance.
But now what I want is (if I actaully had access to the Cat constructor function body, which of course I do not!) something like this:
function Cat() {
this.roarOnInit = function() {
alert(’ROOOAAAR!’);
};
this.roarOnInit();
}
…so that when I do this:
var coolCat = new Cat();
…I actually get that cool ROAR-alert box!
I do understand how to add the method roarOnInit to the Cat constructor (Cat.prototype.roarOnInit = function …) but is there a way that I easily can add the call to the method (which gets executed whenever a Cat instance is created) to the constructor body?
This seems like such a trivial thing, and it’s probably super easy, but I just can’t seem to figure this out this afternoon! Thanks for bearing with me.
UPDATE
Thanks for the answers so far! I did forget one very important thing, and that is that I will not know in advance what the constructor function will be, or it's name etc. This is because I'm running this through a function which accepts any constructor as a parameter, and eventually returns the constructor (with it's original name/prototype) back.
Let's start with this definition of Cat:
function Cat(name){
this.name=name;
}
Cat.prototype.meow=function(){alert(this.name)}
Now, what we can do is to overwrite this with a new constructor that returns a regular Cat, but only after running our script:
var oldCat = Cat;
function Cat(name){
var self=new oldCat(name);
self.roarOnInit=function(){alert("ROOOOAAARRR")};
self.roarOnInit();
return self;
}
We can now do new Cat("Muffin"), and it will roar, and we'll still have access to properties on the original Cat prototype chain. I show this in an example snippet:
// just to be safe, define the original as oldCat()
function oldCat(name){
this.name=name;
}
oldCat.prototype.meow=function(){alert(this.name)}
//var oldCat = Cat;
function Cat(name){
var self=new oldCat(name);
self.roarOnInit=function(){alert("ROOOOAAARRR")};
self.roarOnInit();
return self;
}
var coolCat = new Cat("Muffin");
coolCat.meow();
Now, if you want to abstract this to accept any function, it's not too hard. We just have to do a bit of work with the constructor, to pass arguments. Javascript - Create instance with array of arguments
function injectToConstructor(C){
return function(){
var self = new (C.bind.apply(C,[C].concat([].slice.call(arguments))))();
console.log("object initiated:");
console.log(self);
return self;
};
}
Then we can do something like:
Cat = injectToConstructor(Cat);
var coolCat = new Cat("Muffin"); // logs 2 items
coolCat.meow();
This is because I'm running this through a function which accepts any constructor as a parameter, and eventually returns the constructor (with it's original name/prototype) back.
You cannot really. It's impossible to alter a function's behaviour, no way to "inject" code into it. The only way is to wrap the function, i.e. decorate it, and return a new one.
In your example, it would look like so:
function makeRoarer(constr) {
function Roar() { // new .name and .length, but that shouldn't matter
constr.apply(this, arguments);
this.roarOnInit();
}
Roar.prototype = constr.prototype;
Roar.prototype.constructor = Roar;
Roar.prototype.roarOnInit = function() {
alert(’ROOOAAAR!’);
};
return Roar;
}
class Cat { … } // whatever
var a = new Cat(); // nothing
Cat = makeRoarer(Cat);
var b = new Cat(); // ROOOAAAR!

Javascript - How to create new instance of functions

I know that, we can create the new instance of functions by the following approach. But my question is there any other way to achieve the same?
var Person = function (firstName) {
this.firstName = firstName;
console.log('Person instantiated');
};
var person1 = new Person('Alice');
var person2 = new Person('Bob');
// Show the firstName properties of the objects
console.log('person1 is ' + person1.firstName); // logs "person1 is Alice"
console.log('person2 is ' + person2.firstName); // logs "person2 is Bob"
Since, some time in case of new declaration fails, i am not getting the error too..
Especially, in javascript oops concept requires the different approach.
Some times, I am confusing without even calling the new key words it all works fine.. what is the different between using the new keyword and without using that?
example :
var setColor = function (color) {
return color;
}
var x = setColor('red');
var y = setColor('blue');
console.log(y);
console.log(x);
The new [Function] keyword does many things, but the main things it does are:
Creates a new object
Uses [Function]'s prototype as the parent prototype for the new object
Executes the contents of [Function], using this as a reference to the new object
If you call such a function without new, the this reference will be determined the way it would usually be determined when calling a function, and quite often this would be the global object.
One thing you can do to help catch these mistakes more easily is to use strict mode:
"use strict";
var Person = function (firstName) {
this.firstName = firstName;
console.log('Person instantiated');
};
var person1 = Person('Alice');
If the above code were executed, this would be null instead of the global object, and you would get an error right away instead of having the properties assigned to the global object (and having hard-to-catch bugs).
A way to avoid these kinds of mistakes with new altogether is to simply have the function return a new object instead of being a constructor:
var person = function (firstName) {
console.log('person instantiated');
return {
firstName: firstName
};
};
var person1 = person('Alice');
var person2 = person('Bob');
If you do this, it doesn't matter whether you use new or not, because the function doesn't use this.
Edit There was a question below about prototypes. If you are unfamiliar with prototypes, this is a feature that allows you to specify properties and methods that will be shared between all instances of an object:
"use strict";
var Person = function (firstName) {
this.firstName = firstName;
console.log('Person instantiated');
};
Person.prototype.getMyName = function () {
return this.firstName;
};
var person1 = new Person('Alice');
console.log(person1.getMyName());
If you do this, then all instances created with new Person() will share the getMyName method.
The new-less option I detailed later on does not provide this automatic prototype extension, but there are alternatives:
Option 1 - don't use a prototype:
var person = function (firstName) {
console.log('person instantiated');
return {
firstName: firstName,
getMyName: function () {
return this.firstName;
}
};
};
Option 2 - Use Object.create() to extend the prototype:
var person = function (firstName) {
console.log('person instantiated');
var person = Object.create(person.prototype);
person.firstName = firstName;
return person;
};
Option 3 - Use Object.assign() method to copy the contents of the prototype to a new object:
var person = function (firstName) {
console.log('person instantiated');
return Object.assign({
firstName: firstName
}, person.prototype);
};
Using the new keyword when you call a function sets the context (this) inside the function to be a newly instantiated object, rather than window or some other context, which is why you can assign to this.firstName inside the function, and then refer to it as person1.firstName.
Without using the new keyword, the value of this WONT be a blank object, so you will be assigning to window instead. In this case, you want to use new since you are using the function as a constructor. If you aren't planning to use the function as a constructor, you don't want to call it with new.
Another possible structure using closures and not objects at all
This structure also can be nested creating private static variables
It has no use of the word this
var thing = function(private_var){
function get(){
console.log(private_var)
}
function set(z){
private_var = z
}
return {
get:get,
set:set
}
}
var x = thing(0)
var y = thing(1)
Please note :
This makes certain types of programmers freak out and panic
&& importantly x.say !== y.say
I think you need a bit better understanding of how objects and prototyping work in Javascript.
Consider you have a use case where you want an object that represents a user, and stores their first_name.
Without using any functions, you can simply create an object with your desired properties:
var person = {
first_name: 'joel'
};
This is a standard javascript object - nothing special at all, and no usage of the new keyword to construct it. An alternate syntax to accomplish the same thing would be:
var person = new Object();
person.first_name = 'joel';
Again - this is just a standard object - nothing special at all.
The main reason for creating new instances of a function, is to use javascript's prototyping system. This is similar to a class in other languages. Let's say you wanted all instances of a person to have a method called getName(). You could either make sure you create that method on every person you have...
var person = {
first_name: 'joel',
getName: function() {
return this.first_name;
}
};
or...
var person = new Object();
person.first_name = 'joel';
person.getName = function() {
return this.first_name;
};
However a better approach for this kind of thing, where you're always going to want this method defined for every user, is to create a new instance of a person object, and define the getName method on the prototype property of the Person function:
function Person() {}
Person.prototype.getName = function() {
return this.first_name;
}
var user = new Person();
user.first_name = 'joel';
console.log(user.getName());
... Or as per your example, you can use a parameter to the Person constructor function to set the first name property:
function Person(first_name) {
this.first_name = first_name;
}
Person.prototype.getName = function() {
return this.first_name;
};
var user = new Person('joel');
console.log(user.getName());
Note that using this method you would always use the new keyword when creating a Person instance. The reason for this becomes clear when you consider the followng:
function Person() {this.first_name = 'joel'; return 'test';}
console.log(window.first_name); // Undefined, as expected
console.log(Person()); // Shows "test";
console.log(window.first_name); // shows "joel".
console.log(new Person()); // Shows "{first_name: 'joel'}"
Note that on line 4 above, you can see that by omitting the new keyword on a function call that expects you to be using it, you've accidentally modified a property on the window object, instead of setting it on a new regular object.
Effectively - you can consider usage of the new keyword to cause the return value of the Person function to be disrecarded, and instead you'll be given back a new instance of the Person Object.
Also note that you can reduce the risk of accidental modifying of the window object by omitting the new keyword from inside your function, by checking if this is equal to window and returning a new instance of your function instead:
function Person() {
if (this === window) return new Person();
this.first_name = 'joel';
}
With the above, you can instantiate your person object using either of the following methods and both will have the same effect:
var user1 = new Person();
var user2 = Person();
For some more information on how javascript functions and prototype objects work, I suggest reading http://www.w3schools.com/js/js_object_prototypes.asp

difference between function() {} and new function() {} [duplicate]

This question already has answers here:
`new function()` with lower case "f" in JavaScript
(3 answers)
Closed 9 years ago.
in this question, I don't want to ask "Function", i want to ask "function" puzzle
<script type="text/javascript">
var test = function() {
alert('a');
};
var test1 = new function() {
alert('b');
};
</script>
why it will pop up the "b"?
Function (p1, p2, … , pn, body)
When the Function function is called with some arguments p1, p2, … , pn, body (where n might be 0, that is, there are no “p” arguments, and where body might also not be provided), the following steps are taken:
Create and return a new Function object as if the standard built-in constructor Function was used in a new expression with the same arguments.
check :Is JavaScript's "new" keyword considered harmful?
new function will execute the function, you can use an IIFE (Immediately- Invoked Function Expression) as well:
var test1 = (function() {
alert('b');
}());
new is used for the Factory pattern in Javascript.
It creates and returns an object by executing a constructor function. In your case it doesn't make sense to use new.
Functions which are built to be used as constructors don't require parens, if you aren't passing any arguments:
var Person = function () { this.is_alive = true; },
bob = new Person;
bob.is_alive;
...but any function can be called as a constructor, whether you're using the returned object or not...
new function () { console.log("Bob"); }
this won't save the function anywhere -- it will run it, in place, instantly.
See What is the 'new' keyword in JavaScript? for a basic description of the new keyword.
Essentially, you are calling the constructor to a new object. Let me show you.
var Animal = function(name) {
alert("Animal Created: " + name);
}
jaguar = new Animal("Cool");
The only difference from that and what you did was declare the function in the same line as defining the new object:
jaguar = new function(name) {
alert("Animal Created: " + name);
}
That's why the "b" was printed out.

Forcing the context

I have this class where I have a private property and a public method for access:
Person = function () {
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) { //Get
return this.Name
} else {
this.Name = value; //Set
}
};
return _public;
};
I want to force the context in _public.Name for access a this.Name.
I know the technique of closure, but I want to see if I can force a context.
I found a technique to do it, extend object Function:
Function.prototype.setScope = function (scope) {
var f = this;
return function () {
f().apply(scope);
}
}
And my class becomes:
Person = function () {
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) {
return this.Name
} else {
this.Name = value;
}
}.setScope(this);
return _public;
};
So I can force correctly the context, but I can not pass value and can not, however, return this.Name.
Not
f().apply(scope);
just
f.apply(scope);
(No () after f.) You want to use the apply function on the function f object, not call the function f and access apply on its return value.
To also pass on the arguments that your function in setScope receives, add this:
f.apply(scope, arguments);
arguments is an implicit argument to all functions, which is a pseudo-array of the actual arguments passed to the function at runtime. apply accepts any array-like thing as its second parameter to specify the arguments to use when calling the underlying function.
I'd also have it return the return value:
return f.apply(scope, arguments);
So setScope becomes:
Function.prototype.setScope = function (scope) {
var f = this;
return function () {
return f.apply(scope, arguments);
}
}
Live example
Note that the usual name for this function, and the name it has in the new ECMAScript5 standard, is bind (Section 15.3.4.5; ECMAScript5's bind also lets you curry arguments, which isn't done by this implementation). setScope is a particularly unfortunate name, because it doesn't set the scope, it sets the context.
Having said all that, there's no reason you need setScope in your Person constructor. You can just do this:
Person = function () {
var self = this;
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) {
return self.Name;
} else {
self.Name = value;
}
};
return _public;
};
Live example
But using bind (aka setScope) can be useful in places where you don't want a new closure over the context in which you're doing it.
Off-topic: The way you're specifying Person will break certain things people might expect to work, such as:
var p = new Person();
alert(p instanceof Person); // Expect "true", but in your case will be "false"
...because you're replacing the object new created for you, but returning a different object out of your constructor (which overrides the default).
Rather than creating a new object and returning that in your constructor, allow the object constructed for you by new to be the object (and thus the Person relationship is maintained), but you can still get truly private variables and use accessors:
function Person() {
// Private variable
var name = "asd";
// Accessor function
this.Name = function(value) {
if (typeof value === "undefined") {
return name;
}
name = value;
};
}
Live example
As you can see, this is dramatically simpler, and it preserves the instanceof relationship. Note that we're not qualifying our references to name within Name at all, and so we're using the local variable in the constructor call in which our Name function, which closes over it, was created.
I've also taken the liberty there of giving the constructor function a name, because I'm not a fan of anonymous functions. I should have given the accessor a name as well:
function Person() {
// Private variable
var name = "asd";
// Accessor function
this.Name = Person_Name;
function Person_Name(value) {
if (typeof value === "undefined") {
return name;
}
name = value;
}
}
Off-topic 2: The overwhelming convention in JavaScript code is to use initial caps on function names only for constructor functions (like Person), and not on other kinds of functions (like Name). You're free to do whatever you like, of course, but I thought I'd mention the convention, as it makes it easier for other people to read your code.
Worth noting: All of these techniques result in every single Person object having its own copy of the accessor function. If there are going to be a lot of these objects, that could be a memory issue. If there are only going to be a few, that's fine.
First thing, I think the correct way to go about this is the "closure" method, as the syntax is easier and simpler to understand and makes more sense and most object oriented code written in Javascript is written that way. Another thing to note is that in your method, the "private" member can be accessed from outside by accessing Person.Name (instead of (new Person()).Name).
That being said, it seems that you want something like Prototype.JS's bind method, which allows you to bind a function reference as a method call to a specific object, and also passes all the arguments correctly (including allowing preloaded arguments).
Look at Prototype.JS source for the complete implementation, but a simple implementation of this semantic might look like this:
Function.prototype.bind = function(context) {
var callee = this;
var args = Array.prototype.slice.call(arguments,1);
return function() {
var newargs = args.concat(Array.prototype.slice.call(arguments,0));
return callee.apply(context, newargs);
};
};
It is difficult to understand what you are trying to achieve. But if I guess that you are trying to create a Person class with a name method to get/set the person's name, here is my suggestion:
function Person() {
this._name = undefined; // not required but is better than assigning a fake name
return this;
}
Person.prototype.name = function( _name ) {
if ( _name === undefined ) return this._name; // get
return this._name = _name; // set
}
Note that I have defined the name function with a lower case first letter. This is standard practice in JavaScript where only constructors are usually capitalized. To use this class you do:
person = new Person();
person.name( "Ermes Enea Colella" );
alert( person.name ); // displays "Ermes Enea Colella"
There is no need to bind any context with this method, so you may be looking for something else. If you can clarify your need, I'll be happy to edit my answer.
I hope this helps.

Categories

Resources